mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-09-06 18:05:37 +00:00
Migration Pull request (20230602 vintage)
This PULL request get: - All migration-test patches except last one (daniel) - Documentation about live test cases (peter) Please apply. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEGJn/jt6/WMzuA0uC9IfvGFhy1yMFAmR5yRwACgkQ9IfvGFhy 1yOLQQ/+NsrXEj7Bwp2PdGo+wBRkq4Gah/mc9F00pqtJc2CGNWgfgDohhZjBrhRv cTABsfEcIKgCYqGYwVCklJGlUMzxlJPPcMfvou5SWN59E4FBFSg4DWaBfDPCS8LW yjnz0JcpxJ+Ge0eqP6xpTPKQ0YGisdav/PjF8GZewBCjyrhZop062a92B2t59D8Y shJYKaZZU/5/4zx6KqOm9OClD/yJ+w5q6cGn89/rFE0RMSVywZ3Y1O8/LwIAEP6U oj88rczh3geGlsmtPIeyhA3BdnYuPonmyLz8CINFH9+y2tR9l1dN59q1uwEOIvff BhJvxTNmkTvsi5zeAmbp2CYmRTwhBmlanh8v2OLNj8zlt0cHYNpiYUZO9qxCHIyT LnNTTYhrpqAqINdm+Z8c3ymDKkTz0KECBa45hdFtNB4ZOXPDQTHVqkQRfe3CxDKz f/WM4TxHEzVMw/Ow1K9Kbk7/AEwIV6Ol2BSf9D+ZcU4ydmu6ENhV9G4cQ9Orlv8I opychxf+O/b6yhVFq7J1ufDhfn3aWQmUQC06npEgfrIV/fLrXhYfs2CXkNZs78v6 MTMNPNBN/UasM8hx+ldsjZEHf625lO3eNWoNY1Xxog5YICnNLA+tG6n69uybew2+ UOVyoHwX7iqaToK6bQNCS4H/PjCp3v7fzw1Nsz48Pfaklpivz/k= =4exy -----END PGP SIGNATURE----- Merge tag 'migration-20230602-pull-request' of https://gitlab.com/juan.quintela/qemu into staging Migration Pull request (20230602 vintage) This PULL request get: - All migration-test patches except last one (daniel) - Documentation about live test cases (peter) Please apply. # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEEGJn/jt6/WMzuA0uC9IfvGFhy1yMFAmR5yRwACgkQ9IfvGFhy # 1yOLQQ/+NsrXEj7Bwp2PdGo+wBRkq4Gah/mc9F00pqtJc2CGNWgfgDohhZjBrhRv # cTABsfEcIKgCYqGYwVCklJGlUMzxlJPPcMfvou5SWN59E4FBFSg4DWaBfDPCS8LW # yjnz0JcpxJ+Ge0eqP6xpTPKQ0YGisdav/PjF8GZewBCjyrhZop062a92B2t59D8Y # shJYKaZZU/5/4zx6KqOm9OClD/yJ+w5q6cGn89/rFE0RMSVywZ3Y1O8/LwIAEP6U # oj88rczh3geGlsmtPIeyhA3BdnYuPonmyLz8CINFH9+y2tR9l1dN59q1uwEOIvff # BhJvxTNmkTvsi5zeAmbp2CYmRTwhBmlanh8v2OLNj8zlt0cHYNpiYUZO9qxCHIyT # LnNTTYhrpqAqINdm+Z8c3ymDKkTz0KECBa45hdFtNB4ZOXPDQTHVqkQRfe3CxDKz # f/WM4TxHEzVMw/Ow1K9Kbk7/AEwIV6Ol2BSf9D+ZcU4ydmu6ENhV9G4cQ9Orlv8I # opychxf+O/b6yhVFq7J1ufDhfn3aWQmUQC06npEgfrIV/fLrXhYfs2CXkNZs78v6 # MTMNPNBN/UasM8hx+ldsjZEHf625lO3eNWoNY1Xxog5YICnNLA+tG6n69uybew2+ # UOVyoHwX7iqaToK6bQNCS4H/PjCp3v7fzw1Nsz48Pfaklpivz/k= # =4exy # -----END PGP SIGNATURE----- # gpg: Signature made Fri 02 Jun 2023 03:49:00 AM PDT # gpg: using RSA key 1899FF8EDEBF58CCEE034B82F487EF185872D723 # gpg: Good signature from "Juan Quintela <quintela@redhat.com>" [unknown] # gpg: aka "Juan Quintela <quintela@trasno.org>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 1899 FF8E DEBF 58CC EE03 4B82 F487 EF18 5872 D723 * tag 'migration-20230602-pull-request' of https://gitlab.com/juan.quintela/qemu: qtest/migration: Document live=true cases tests/qtest: make more migration pre-copy scenarios run non-live tests/qtest: distinguish src/dst migration VM stop/resume events tests/qtest: capture RESUME events during migration tests/qtest: replace wait_command() with qtest_qmp_assert_success tests/qtest: switch to using event callbacks for STOP event tests/qtest: get rid of some 'qtest_qmp' usage in migration test tests/qtest: get rid of 'qmp_command' helper in migration test tests/qtest: add support for callback to receive QMP events tests/qtest: add various qtest_qmp_assert_success() variants Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
848a6caa88
|
@ -82,6 +82,8 @@ struct QTestState
|
|||
GString *rx;
|
||||
QTestTransportOps ops;
|
||||
GList *pending_events;
|
||||
QTestQMPEventCallback eventCB;
|
||||
void *eventData;
|
||||
};
|
||||
|
||||
static GHookList abrt_hooks;
|
||||
|
@ -703,10 +705,15 @@ QDict *qtest_qmp_receive(QTestState *s)
|
|||
if (!qdict_get_try_str(response, "event")) {
|
||||
return response;
|
||||
}
|
||||
|
||||
if (!s->eventCB ||
|
||||
!s->eventCB(s, qdict_get_str(response, "event"),
|
||||
response, s->eventData)) {
|
||||
/* Stash the event for a later consumption */
|
||||
s->pending_events = g_list_append(s->pending_events, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QDict *qtest_qmp_receive_dict(QTestState *s)
|
||||
{
|
||||
|
@ -808,6 +815,13 @@ void qtest_qmp_send_raw(QTestState *s, const char *fmt, ...)
|
|||
va_end(ap);
|
||||
}
|
||||
|
||||
void qtest_qmp_set_event_callback(QTestState *s,
|
||||
QTestQMPEventCallback cb, void *opaque)
|
||||
{
|
||||
s->eventCB = cb;
|
||||
s->eventData = opaque;
|
||||
}
|
||||
|
||||
QDict *qtest_qmp_event_ref(QTestState *s, const char *event)
|
||||
{
|
||||
while (s->pending_events) {
|
||||
|
@ -1229,25 +1243,108 @@ void qtest_memset(QTestState *s, uint64_t addr, uint8_t pattern, size_t size)
|
|||
qtest_rsp(s);
|
||||
}
|
||||
|
||||
void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...)
|
||||
QDict *qtest_vqmp_assert_success_ref(QTestState *qts,
|
||||
const char *fmt, va_list args)
|
||||
{
|
||||
va_list ap;
|
||||
QDict *response;
|
||||
QDict *ret;
|
||||
|
||||
va_start(ap, fmt);
|
||||
response = qtest_vqmp(qts, fmt, ap);
|
||||
va_end(ap);
|
||||
response = qtest_vqmp(qts, fmt, args);
|
||||
|
||||
g_assert(response);
|
||||
if (!qdict_haskey(response, "return")) {
|
||||
GString *s = qobject_to_json_pretty(QOBJECT(response), true);
|
||||
g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(response), true);
|
||||
g_test_message("%s", s->str);
|
||||
g_string_free(s, true);
|
||||
}
|
||||
g_assert(qdict_haskey(response, "return"));
|
||||
ret = qdict_get_qdict(response, "return");
|
||||
qobject_ref(ret);
|
||||
qobject_unref(response);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void qtest_vqmp_assert_success(QTestState *qts,
|
||||
const char *fmt, va_list args)
|
||||
{
|
||||
QDict *response;
|
||||
|
||||
response = qtest_vqmp_assert_success_ref(qts, fmt, args);
|
||||
|
||||
qobject_unref(response);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
QDict *qtest_vqmp_fds_assert_success_ref(QTestState *qts, int *fds, size_t nfds,
|
||||
const char *fmt, va_list args)
|
||||
{
|
||||
QDict *response;
|
||||
QDict *ret;
|
||||
|
||||
response = qtest_vqmp_fds(qts, fds, nfds, fmt, args);
|
||||
|
||||
g_assert(response);
|
||||
if (!qdict_haskey(response, "return")) {
|
||||
g_autoptr(GString) s = qobject_to_json_pretty(QOBJECT(response), true);
|
||||
g_test_message("%s", s->str);
|
||||
}
|
||||
g_assert(qdict_haskey(response, "return"));
|
||||
ret = qdict_get_qdict(response, "return");
|
||||
qobject_ref(ret);
|
||||
qobject_unref(response);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void qtest_vqmp_fds_assert_success(QTestState *qts, int *fds, size_t nfds,
|
||||
const char *fmt, va_list args)
|
||||
{
|
||||
QDict *response;
|
||||
response = qtest_vqmp_fds_assert_success_ref(qts, fds, nfds, fmt, args);
|
||||
qobject_unref(response);
|
||||
}
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
QDict *qtest_qmp_assert_success_ref(QTestState *qts, const char *fmt, ...)
|
||||
{
|
||||
QDict *response;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
response = qtest_vqmp_assert_success_ref(qts, fmt, ap);
|
||||
va_end(ap);
|
||||
return response;
|
||||
}
|
||||
|
||||
void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
qtest_vqmp_assert_success(qts, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
QDict *qtest_qmp_fds_assert_success_ref(QTestState *qts, int *fds, size_t nfds,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
QDict *response;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
response = qtest_vqmp_fds_assert_success_ref(qts, fds, nfds, fmt, ap);
|
||||
va_end(ap);
|
||||
return response;
|
||||
}
|
||||
|
||||
void qtest_qmp_fds_assert_success(QTestState *qts, int *fds, size_t nfds,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
qtest_vqmp_fds_assert_success(qts, fds, nfds, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
bool qtest_big_endian(QTestState *s)
|
||||
{
|
||||
return s->big_endian;
|
||||
|
|
|
@ -238,17 +238,52 @@ QDict *qtest_qmp_receive_dict(QTestState *s);
|
|||
* @s: #QTestState instance to operate on.
|
||||
*
|
||||
* Reads a QMP message from QEMU and returns the response.
|
||||
* Buffers all the events received meanwhile, until a
|
||||
* call to qtest_qmp_eventwait
|
||||
*
|
||||
* If a callback is registered with qtest_qmp_set_event_callback,
|
||||
* it will be invoked for every event seen, otherwise events
|
||||
* will be buffered until a call to one of the qtest_qmp_eventwait
|
||||
* family of functions.
|
||||
*/
|
||||
QDict *qtest_qmp_receive(QTestState *s);
|
||||
|
||||
/*
|
||||
* QTestQMPEventCallback:
|
||||
* @s: #QTestState instance event was received on
|
||||
* @name: name of the event type
|
||||
* @event: #QDict for the event details
|
||||
* @opaque: opaque data from time of callback registration
|
||||
*
|
||||
* This callback will be invoked whenever an event is received.
|
||||
* If the callback returns true the event will be consumed,
|
||||
* otherwise it will be put on the list of pending events.
|
||||
* Pending events can be later handled by calling either
|
||||
* qtest_qmp_eventwait or qtest_qmp_eventwait_ref.
|
||||
*
|
||||
* Return: true to consume the event, false to let it be queued
|
||||
*/
|
||||
typedef bool (*QTestQMPEventCallback)(QTestState *s, const char *name,
|
||||
QDict *event, void *opaque);
|
||||
|
||||
/**
|
||||
* qtest_qmp_set_event_callback:
|
||||
* @s: #QTestSTate instance to operate on
|
||||
* @cb: callback to invoke for events
|
||||
* @opaque: data to pass to @cb
|
||||
*
|
||||
* Register a callback to be invoked whenever an event arrives
|
||||
*/
|
||||
void qtest_qmp_set_event_callback(QTestState *s,
|
||||
QTestQMPEventCallback cb, void *opaque);
|
||||
|
||||
/**
|
||||
* qtest_qmp_eventwait:
|
||||
* @s: #QTestState instance to operate on.
|
||||
* @event: event to wait for.
|
||||
*
|
||||
* Continuously polls for QMP responses until it receives the desired event.
|
||||
*
|
||||
* Any callback registered with qtest_qmp_set_event_callback will
|
||||
* be invoked for every event seen.
|
||||
*/
|
||||
void qtest_qmp_eventwait(QTestState *s, const char *event);
|
||||
|
||||
|
@ -258,6 +293,10 @@ void qtest_qmp_eventwait(QTestState *s, const char *event);
|
|||
* @event: event to wait for.
|
||||
*
|
||||
* Continuously polls for QMP responses until it receives the desired event.
|
||||
*
|
||||
* Any callback registered with qtest_qmp_set_event_callback will
|
||||
* be invoked for every event seen.
|
||||
*
|
||||
* Returns a copy of the event for further investigation.
|
||||
*/
|
||||
QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event);
|
||||
|
@ -693,6 +732,86 @@ void qtest_add_abrt_handler(GHookFunc fn, const void *data);
|
|||
*/
|
||||
void qtest_remove_abrt_handler(void *data);
|
||||
|
||||
/**
|
||||
* qtest_vqmp_assert_success_ref:
|
||||
* @qts: QTestState instance to operate on
|
||||
* @fmt: QMP message to send to qemu, formatted like
|
||||
* qobject_from_jsonf_nofail(). See parse_interpolation() for what's
|
||||
* supported after '%'.
|
||||
* @args: variable arguments for @fmt
|
||||
*
|
||||
* Sends a QMP message to QEMU, asserts that a 'return' key is present in
|
||||
* the response, and returns the response.
|
||||
*/
|
||||
QDict *qtest_vqmp_assert_success_ref(QTestState *qts,
|
||||
const char *fmt, va_list args)
|
||||
G_GNUC_PRINTF(2, 0);
|
||||
|
||||
/**
|
||||
* qtest_vqmp_assert_success:
|
||||
* @qts: QTestState instance to operate on
|
||||
* @fmt: QMP message to send to qemu, formatted like
|
||||
* qobject_from_jsonf_nofail(). See parse_interpolation() for what's
|
||||
* supported after '%'.
|
||||
* @args: variable arguments for @fmt
|
||||
*
|
||||
* Sends a QMP message to QEMU and asserts that a 'return' key is present in
|
||||
* the response.
|
||||
*/
|
||||
void qtest_vqmp_assert_success(QTestState *qts,
|
||||
const char *fmt, va_list args)
|
||||
G_GNUC_PRINTF(2, 0);
|
||||
|
||||
#ifndef _WIN32
|
||||
/**
|
||||
* qtest_vqmp_fds_assert_success_ref:
|
||||
* @qts: QTestState instance to operate on
|
||||
* @fds: the file descriptors to send
|
||||
* @nfds: number of @fds to send
|
||||
* @fmt: QMP message to send to qemu, formatted like
|
||||
* qobject_from_jsonf_nofail(). See parse_interpolation() for what's
|
||||
* supported after '%'.
|
||||
* @args: variable arguments for @fmt
|
||||
*
|
||||
* Sends a QMP message with file descriptors to QEMU,
|
||||
* asserts that a 'return' key is present in the response,
|
||||
* and returns the response.
|
||||
*/
|
||||
QDict *qtest_vqmp_fds_assert_success_ref(QTestState *qts, int *fds, size_t nfds,
|
||||
const char *fmt, va_list args)
|
||||
G_GNUC_PRINTF(4, 0);
|
||||
|
||||
/**
|
||||
* qtest_vqmp_fds_assert_success:
|
||||
* @qts: QTestState instance to operate on
|
||||
* @fds: the file descriptors to send
|
||||
* @nfds: number of @fds to send
|
||||
* @fmt: QMP message to send to qemu, formatted like
|
||||
* qobject_from_jsonf_nofail(). See parse_interpolation() for what's
|
||||
* supported after '%'.
|
||||
* @args: variable arguments for @fmt
|
||||
*
|
||||
* Sends a QMP message with file descriptors to QEMU and
|
||||
* asserts that a 'return' key is present in the response.
|
||||
*/
|
||||
void qtest_vqmp_fds_assert_success(QTestState *qts, int *fds, size_t nfds,
|
||||
const char *fmt, va_list args)
|
||||
G_GNUC_PRINTF(4, 0);
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
/**
|
||||
* qtest_qmp_assert_success_ref:
|
||||
* @qts: QTestState instance to operate on
|
||||
* @fmt: QMP message to send to qemu, formatted like
|
||||
* qobject_from_jsonf_nofail(). See parse_interpolation() for what's
|
||||
* supported after '%'.
|
||||
*
|
||||
* Sends a QMP message to QEMU, asserts that a 'return' key is present in
|
||||
* the response, and returns the response.
|
||||
*/
|
||||
QDict *qtest_qmp_assert_success_ref(QTestState *qts, const char *fmt, ...)
|
||||
G_GNUC_PRINTF(2, 3);
|
||||
|
||||
/**
|
||||
* qtest_qmp_assert_success:
|
||||
* @qts: QTestState instance to operate on
|
||||
|
@ -706,6 +825,41 @@ void qtest_remove_abrt_handler(void *data);
|
|||
void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...)
|
||||
G_GNUC_PRINTF(2, 3);
|
||||
|
||||
#ifndef _WIN32
|
||||
/**
|
||||
* qtest_qmp_fd_assert_success_ref:
|
||||
* @qts: QTestState instance to operate on
|
||||
* @fds: the file descriptors to send
|
||||
* @nfds: number of @fds to send
|
||||
* @fmt: QMP message to send to qemu, formatted like
|
||||
* qobject_from_jsonf_nofail(). See parse_interpolation() for what's
|
||||
* supported after '%'.
|
||||
*
|
||||
* Sends a QMP message with file descriptors to QEMU,
|
||||
* asserts that a 'return' key is present in the response,
|
||||
* and returns the response.
|
||||
*/
|
||||
QDict *qtest_qmp_fds_assert_success_ref(QTestState *qts, int *fds, size_t nfds,
|
||||
const char *fmt, ...)
|
||||
G_GNUC_PRINTF(4, 5);
|
||||
|
||||
/**
|
||||
* qtest_qmp_fd_assert_success:
|
||||
* @qts: QTestState instance to operate on
|
||||
* @fds: the file descriptors to send
|
||||
* @nfds: number of @fds to send
|
||||
* @fmt: QMP message to send to qemu, formatted like
|
||||
* qobject_from_jsonf_nofail(). See parse_interpolation() for what's
|
||||
* supported after '%'.
|
||||
*
|
||||
* Sends a QMP message with file descriptors to QEMU and
|
||||
* asserts that a 'return' key is present in the response.
|
||||
*/
|
||||
void qtest_qmp_fds_assert_success(QTestState *qts, int *fds, size_t nfds,
|
||||
const char *fmt, ...)
|
||||
G_GNUC_PRINTF(4, 5);
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
/**
|
||||
* qtest_cb_for_every_machine:
|
||||
* @cb: Pointer to the callback function
|
||||
|
|
|
@ -23,88 +23,30 @@
|
|||
*/
|
||||
#define MIGRATION_STATUS_WAIT_TIMEOUT 120
|
||||
|
||||
bool got_stop;
|
||||
|
||||
static void check_stop_event(QTestState *who)
|
||||
bool migrate_watch_for_stop(QTestState *who, const char *name,
|
||||
QDict *event, void *opaque)
|
||||
{
|
||||
QDict *event = qtest_qmp_event_ref(who, "STOP");
|
||||
if (event) {
|
||||
got_stop = true;
|
||||
qobject_unref(event);
|
||||
}
|
||||
bool *seen = opaque;
|
||||
|
||||
if (g_str_equal(name, "STOP")) {
|
||||
*seen = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/*
|
||||
* Events can get in the way of responses we are actually waiting for.
|
||||
*/
|
||||
QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...)
|
||||
{
|
||||
va_list ap;
|
||||
QDict *resp, *ret;
|
||||
|
||||
va_start(ap, command);
|
||||
qtest_qmp_vsend_fds(who, &fd, 1, command, ap);
|
||||
va_end(ap);
|
||||
|
||||
resp = qtest_qmp_receive(who);
|
||||
check_stop_event(who);
|
||||
|
||||
g_assert(!qdict_haskey(resp, "error"));
|
||||
g_assert(qdict_haskey(resp, "return"));
|
||||
|
||||
ret = qdict_get_qdict(resp, "return");
|
||||
qobject_ref(ret);
|
||||
qobject_unref(resp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Events can get in the way of responses we are actually waiting for.
|
||||
*/
|
||||
QDict *wait_command(QTestState *who, const char *command, ...)
|
||||
{
|
||||
va_list ap;
|
||||
QDict *resp, *ret;
|
||||
|
||||
va_start(ap, command);
|
||||
resp = qtest_vqmp(who, command, ap);
|
||||
va_end(ap);
|
||||
|
||||
check_stop_event(who);
|
||||
|
||||
g_assert(!qdict_haskey(resp, "error"));
|
||||
g_assert(qdict_haskey(resp, "return"));
|
||||
|
||||
ret = qdict_get_qdict(resp, "return");
|
||||
qobject_ref(ret);
|
||||
qobject_unref(resp);
|
||||
|
||||
return ret;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute the qmp command only
|
||||
*/
|
||||
QDict *qmp_command(QTestState *who, const char *command, ...)
|
||||
bool migrate_watch_for_resume(QTestState *who, const char *name,
|
||||
QDict *event, void *opaque)
|
||||
{
|
||||
va_list ap;
|
||||
QDict *resp, *ret;
|
||||
bool *seen = opaque;
|
||||
|
||||
va_start(ap, command);
|
||||
resp = qtest_vqmp(who, command, ap);
|
||||
va_end(ap);
|
||||
if (g_str_equal(name, "RESUME")) {
|
||||
*seen = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
g_assert(!qdict_haskey(resp, "error"));
|
||||
g_assert(qdict_haskey(resp, "return"));
|
||||
|
||||
ret = qdict_get_qdict(resp, "return");
|
||||
qobject_ref(ret);
|
||||
qobject_unref(resp);
|
||||
|
||||
return ret;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -115,7 +57,7 @@ QDict *qmp_command(QTestState *who, const char *command, ...)
|
|||
void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
QDict *args, *rsp;
|
||||
QDict *args;
|
||||
|
||||
va_start(ap, fmt);
|
||||
args = qdict_from_vjsonf_nofail(fmt, ap);
|
||||
|
@ -124,10 +66,8 @@ void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...)
|
|||
g_assert(!qdict_haskey(args, "uri"));
|
||||
qdict_put_str(args, "uri", uri);
|
||||
|
||||
rsp = qtest_qmp(who, "{ 'execute': 'migrate', 'arguments': %p}", args);
|
||||
|
||||
g_assert(qdict_haskey(rsp, "return"));
|
||||
qobject_unref(rsp);
|
||||
qtest_qmp_assert_success(who,
|
||||
"{ 'execute': 'migrate', 'arguments': %p}", args);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -136,7 +76,7 @@ void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...)
|
|||
*/
|
||||
QDict *migrate_query(QTestState *who)
|
||||
{
|
||||
return wait_command(who, "{ 'execute': 'query-migrate' }");
|
||||
return qtest_qmp_assert_success_ref(who, "{ 'execute': 'query-migrate' }");
|
||||
}
|
||||
|
||||
QDict *migrate_query_not_failed(QTestState *who)
|
||||
|
@ -234,7 +174,8 @@ void wait_for_migration_fail(QTestState *from, bool allow_active)
|
|||
} while (!failed);
|
||||
|
||||
/* Is the machine currently running? */
|
||||
rsp_return = wait_command(from, "{ 'execute': 'query-status' }");
|
||||
rsp_return = qtest_qmp_assert_success_ref(from,
|
||||
"{ 'execute': 'query-status' }");
|
||||
g_assert(qdict_haskey(rsp_return, "running"));
|
||||
g_assert(qdict_get_bool(rsp_return, "running"));
|
||||
qobject_unref(rsp_return);
|
||||
|
|
|
@ -15,18 +15,10 @@
|
|||
|
||||
#include "libqtest.h"
|
||||
|
||||
extern bool got_stop;
|
||||
|
||||
#ifndef _WIN32
|
||||
G_GNUC_PRINTF(3, 4)
|
||||
QDict *wait_command_fd(QTestState *who, int fd, const char *command, ...);
|
||||
#endif
|
||||
|
||||
G_GNUC_PRINTF(2, 3)
|
||||
QDict *wait_command(QTestState *who, const char *command, ...);
|
||||
|
||||
G_GNUC_PRINTF(2, 3)
|
||||
QDict *qmp_command(QTestState *who, const char *command, ...);
|
||||
bool migrate_watch_for_stop(QTestState *who, const char *name,
|
||||
QDict *event, void *opaque);
|
||||
bool migrate_watch_for_resume(QTestState *who, const char *name,
|
||||
QDict *event, void *opaque);
|
||||
|
||||
G_GNUC_PRINTF(3, 4)
|
||||
void migrate_qmp(QTestState *who, const char *uri, const char *fmt, ...);
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
unsigned start_address;
|
||||
unsigned end_address;
|
||||
static bool uffd_feature_thread_id;
|
||||
static bool got_src_stop;
|
||||
static bool got_dst_resume;
|
||||
|
||||
/*
|
||||
* Dirtylimit stop working if dirty page rate error
|
||||
|
@ -225,7 +227,7 @@ static void wait_for_migration_pass(QTestState *who)
|
|||
uint64_t pass;
|
||||
|
||||
/* Wait for the 1st sync */
|
||||
while (!got_stop && !initial_pass) {
|
||||
while (!got_src_stop && !initial_pass) {
|
||||
usleep(1000);
|
||||
initial_pass = get_migration_pass(who);
|
||||
}
|
||||
|
@ -233,7 +235,7 @@ static void wait_for_migration_pass(QTestState *who)
|
|||
do {
|
||||
usleep(1000);
|
||||
pass = get_migration_pass(who);
|
||||
} while (pass == initial_pass && !got_stop);
|
||||
} while (pass == initial_pass && !got_src_stop);
|
||||
}
|
||||
|
||||
static void check_guests_ram(QTestState *who)
|
||||
|
@ -341,7 +343,8 @@ static long long migrate_get_parameter_int(QTestState *who,
|
|||
QDict *rsp;
|
||||
long long result;
|
||||
|
||||
rsp = wait_command(who, "{ 'execute': 'query-migrate-parameters' }");
|
||||
rsp = qtest_qmp_assert_success_ref(
|
||||
who, "{ 'execute': 'query-migrate-parameters' }");
|
||||
result = qdict_get_int(rsp, parameter);
|
||||
qobject_unref(rsp);
|
||||
return result;
|
||||
|
@ -359,14 +362,10 @@ static void migrate_check_parameter_int(QTestState *who, const char *parameter,
|
|||
static void migrate_set_parameter_int(QTestState *who, const char *parameter,
|
||||
long long value)
|
||||
{
|
||||
QDict *rsp;
|
||||
|
||||
rsp = qtest_qmp(who,
|
||||
qtest_qmp_assert_success(who,
|
||||
"{ 'execute': 'migrate-set-parameters',"
|
||||
"'arguments': { %s: %lld } }",
|
||||
parameter, value);
|
||||
g_assert(qdict_haskey(rsp, "return"));
|
||||
qobject_unref(rsp);
|
||||
migrate_check_parameter_int(who, parameter, value);
|
||||
}
|
||||
|
||||
|
@ -376,7 +375,8 @@ static char *migrate_get_parameter_str(QTestState *who,
|
|||
QDict *rsp;
|
||||
char *result;
|
||||
|
||||
rsp = wait_command(who, "{ 'execute': 'query-migrate-parameters' }");
|
||||
rsp = qtest_qmp_assert_success_ref(
|
||||
who, "{ 'execute': 'query-migrate-parameters' }");
|
||||
result = g_strdup(qdict_get_str(rsp, parameter));
|
||||
qobject_unref(rsp);
|
||||
return result;
|
||||
|
@ -392,14 +392,10 @@ static void migrate_check_parameter_str(QTestState *who, const char *parameter,
|
|||
static void migrate_set_parameter_str(QTestState *who, const char *parameter,
|
||||
const char *value)
|
||||
{
|
||||
QDict *rsp;
|
||||
|
||||
rsp = qtest_qmp(who,
|
||||
qtest_qmp_assert_success(who,
|
||||
"{ 'execute': 'migrate-set-parameters',"
|
||||
"'arguments': { %s: %s } }",
|
||||
parameter, value);
|
||||
g_assert(qdict_haskey(rsp, "return"));
|
||||
qobject_unref(rsp);
|
||||
migrate_check_parameter_str(who, parameter, value);
|
||||
}
|
||||
|
||||
|
@ -409,7 +405,8 @@ static long long migrate_get_parameter_bool(QTestState *who,
|
|||
QDict *rsp;
|
||||
int result;
|
||||
|
||||
rsp = wait_command(who, "{ 'execute': 'query-migrate-parameters' }");
|
||||
rsp = qtest_qmp_assert_success_ref(
|
||||
who, "{ 'execute': 'query-migrate-parameters' }");
|
||||
result = qdict_get_bool(rsp, parameter);
|
||||
qobject_unref(rsp);
|
||||
return !!result;
|
||||
|
@ -427,14 +424,10 @@ static void migrate_check_parameter_bool(QTestState *who, const char *parameter,
|
|||
static void migrate_set_parameter_bool(QTestState *who, const char *parameter,
|
||||
int value)
|
||||
{
|
||||
QDict *rsp;
|
||||
|
||||
rsp = qtest_qmp(who,
|
||||
qtest_qmp_assert_success(who,
|
||||
"{ 'execute': 'migrate-set-parameters',"
|
||||
"'arguments': { %s: %i } }",
|
||||
parameter, value);
|
||||
g_assert(qdict_haskey(rsp, "return"));
|
||||
qobject_unref(rsp);
|
||||
migrate_check_parameter_bool(who, parameter, value);
|
||||
}
|
||||
|
||||
|
@ -454,66 +447,47 @@ static void migrate_ensure_converge(QTestState *who)
|
|||
|
||||
static void migrate_pause(QTestState *who)
|
||||
{
|
||||
QDict *rsp;
|
||||
|
||||
rsp = wait_command(who, "{ 'execute': 'migrate-pause' }");
|
||||
qobject_unref(rsp);
|
||||
qtest_qmp_assert_success(who, "{ 'execute': 'migrate-pause' }");
|
||||
}
|
||||
|
||||
static void migrate_continue(QTestState *who, const char *state)
|
||||
{
|
||||
QDict *rsp;
|
||||
|
||||
rsp = wait_command(who,
|
||||
qtest_qmp_assert_success(who,
|
||||
"{ 'execute': 'migrate-continue',"
|
||||
" 'arguments': { 'state': %s } }",
|
||||
state);
|
||||
qobject_unref(rsp);
|
||||
}
|
||||
|
||||
static void migrate_recover(QTestState *who, const char *uri)
|
||||
{
|
||||
QDict *rsp;
|
||||
|
||||
rsp = wait_command(who,
|
||||
qtest_qmp_assert_success(who,
|
||||
"{ 'execute': 'migrate-recover', "
|
||||
" 'id': 'recover-cmd', "
|
||||
" 'arguments': { 'uri': %s } }",
|
||||
uri);
|
||||
qobject_unref(rsp);
|
||||
}
|
||||
|
||||
static void migrate_cancel(QTestState *who)
|
||||
{
|
||||
QDict *rsp;
|
||||
|
||||
rsp = wait_command(who, "{ 'execute': 'migrate_cancel' }");
|
||||
qobject_unref(rsp);
|
||||
qtest_qmp_assert_success(who, "{ 'execute': 'migrate_cancel' }");
|
||||
}
|
||||
|
||||
static void migrate_set_capability(QTestState *who, const char *capability,
|
||||
bool value)
|
||||
{
|
||||
QDict *rsp;
|
||||
|
||||
rsp = qtest_qmp(who,
|
||||
qtest_qmp_assert_success(who,
|
||||
"{ 'execute': 'migrate-set-capabilities',"
|
||||
"'arguments': { "
|
||||
"'capabilities': [ { "
|
||||
"'capability': %s, 'state': %i } ] } }",
|
||||
capability, value);
|
||||
g_assert(qdict_haskey(rsp, "return"));
|
||||
qobject_unref(rsp);
|
||||
}
|
||||
|
||||
static void migrate_postcopy_start(QTestState *from, QTestState *to)
|
||||
{
|
||||
QDict *rsp;
|
||||
qtest_qmp_assert_success(from, "{ 'execute': 'migrate-start-postcopy' }");
|
||||
|
||||
rsp = wait_command(from, "{ 'execute': 'migrate-start-postcopy' }");
|
||||
qobject_unref(rsp);
|
||||
|
||||
if (!got_stop) {
|
||||
if (!got_src_stop) {
|
||||
qtest_qmp_eventwait(from, "STOP");
|
||||
}
|
||||
|
||||
|
@ -603,9 +577,19 @@ typedef struct {
|
|||
MIG_TEST_FAIL_DEST_QUIT_ERR,
|
||||
} result;
|
||||
|
||||
/* Optional: set number of migration passes to wait for */
|
||||
/* Optional: set number of migration passes to wait for, if live==true */
|
||||
unsigned int iterations;
|
||||
|
||||
/*
|
||||
* Optional: whether the guest CPUs should be running during a precopy
|
||||
* migration test. We used to always run with live but it took much
|
||||
* longer so we reduced live tests to only the ones that have solid
|
||||
* reason to be tested live-only. For each of the new test cases for
|
||||
* precopy please provide justifications to use live explicitly (please
|
||||
* refer to existing ones with live=true), or use live=off by default.
|
||||
*/
|
||||
bool live;
|
||||
|
||||
/* Postcopy specific fields */
|
||||
void *postcopy_data;
|
||||
bool postcopy_preempt;
|
||||
|
@ -633,7 +617,8 @@ static int test_migrate_start(QTestState **from, QTestState **to,
|
|||
}
|
||||
}
|
||||
|
||||
got_stop = false;
|
||||
got_src_stop = false;
|
||||
got_dst_resume = false;
|
||||
bootpath = g_strdup_printf("%s/bootsect", tmpfs);
|
||||
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
|
||||
/* the assembled x86 boot sector should be exactly one sector large */
|
||||
|
@ -719,6 +704,9 @@ static int test_migrate_start(QTestState **from, QTestState **to,
|
|||
ignore_stderr);
|
||||
if (!args->only_target) {
|
||||
*from = qtest_init(cmd_source);
|
||||
qtest_qmp_set_event_callback(*from,
|
||||
migrate_watch_for_stop,
|
||||
&got_src_stop);
|
||||
}
|
||||
|
||||
cmd_target = g_strdup_printf("-accel kvm%s -accel tcg%s%s "
|
||||
|
@ -736,6 +724,9 @@ static int test_migrate_start(QTestState **from, QTestState **to,
|
|||
args->opts_target ? args->opts_target : "",
|
||||
ignore_stderr);
|
||||
*to = qtest_init(cmd_target);
|
||||
qtest_qmp_set_event_callback(*to,
|
||||
migrate_watch_for_resume,
|
||||
&got_dst_resume);
|
||||
|
||||
/*
|
||||
* Remove shmem file immediately to avoid memory leak in test failed case.
|
||||
|
@ -797,7 +788,6 @@ test_migrate_tls_psk_start_common(QTestState *from,
|
|||
{
|
||||
struct TestMigrateTLSPSKData *data =
|
||||
g_new0(struct TestMigrateTLSPSKData, 1);
|
||||
QDict *rsp;
|
||||
|
||||
data->workdir = g_strdup_printf("%s/tlscredspsk0", tmpfs);
|
||||
data->pskfile = g_strdup_printf("%s/%s", data->workdir,
|
||||
|
@ -813,7 +803,7 @@ test_migrate_tls_psk_start_common(QTestState *from,
|
|||
test_tls_psk_init_alt(data->pskfilealt);
|
||||
}
|
||||
|
||||
rsp = wait_command(from,
|
||||
qtest_qmp_assert_success(from,
|
||||
"{ 'execute': 'object-add',"
|
||||
" 'arguments': { 'qom-type': 'tls-creds-psk',"
|
||||
" 'id': 'tlscredspsk0',"
|
||||
|
@ -821,16 +811,14 @@ test_migrate_tls_psk_start_common(QTestState *from,
|
|||
" 'dir': %s,"
|
||||
" 'username': 'qemu'} }",
|
||||
data->workdir);
|
||||
qobject_unref(rsp);
|
||||
|
||||
rsp = wait_command(to,
|
||||
qtest_qmp_assert_success(to,
|
||||
"{ 'execute': 'object-add',"
|
||||
" 'arguments': { 'qom-type': 'tls-creds-psk',"
|
||||
" 'id': 'tlscredspsk0',"
|
||||
" 'endpoint': 'server',"
|
||||
" 'dir': %s } }",
|
||||
mismatch ? data->workdiralt : data->workdir);
|
||||
qobject_unref(rsp);
|
||||
|
||||
migrate_set_parameter_str(from, "tls-creds", "tlscredspsk0");
|
||||
migrate_set_parameter_str(to, "tls-creds", "tlscredspsk0");
|
||||
|
@ -901,7 +889,6 @@ test_migrate_tls_x509_start_common(QTestState *from,
|
|||
TestMigrateTLSX509 *args)
|
||||
{
|
||||
TestMigrateTLSX509Data *data = g_new0(TestMigrateTLSX509Data, 1);
|
||||
QDict *rsp;
|
||||
|
||||
data->workdir = g_strdup_printf("%s/tlscredsx5090", tmpfs);
|
||||
data->keyfile = g_strdup_printf("%s/key.pem", data->workdir);
|
||||
|
@ -944,7 +931,7 @@ test_migrate_tls_x509_start_common(QTestState *from,
|
|||
args->certhostname,
|
||||
args->certipaddr);
|
||||
|
||||
rsp = wait_command(from,
|
||||
qtest_qmp_assert_success(from,
|
||||
"{ 'execute': 'object-add',"
|
||||
" 'arguments': { 'qom-type': 'tls-creds-x509',"
|
||||
" 'id': 'tlscredsx509client0',"
|
||||
|
@ -953,13 +940,12 @@ test_migrate_tls_x509_start_common(QTestState *from,
|
|||
" 'sanity-check': true,"
|
||||
" 'verify-peer': true} }",
|
||||
data->workdir);
|
||||
qobject_unref(rsp);
|
||||
migrate_set_parameter_str(from, "tls-creds", "tlscredsx509client0");
|
||||
if (args->certhostname) {
|
||||
migrate_set_parameter_str(from, "tls-hostname", args->certhostname);
|
||||
}
|
||||
|
||||
rsp = wait_command(to,
|
||||
qtest_qmp_assert_success(to,
|
||||
"{ 'execute': 'object-add',"
|
||||
" 'arguments': { 'qom-type': 'tls-creds-x509',"
|
||||
" 'id': 'tlscredsx509server0',"
|
||||
|
@ -968,11 +954,10 @@ test_migrate_tls_x509_start_common(QTestState *from,
|
|||
" 'sanity-check': true,"
|
||||
" 'verify-peer': %i} }",
|
||||
data->workdir, args->verifyclient);
|
||||
qobject_unref(rsp);
|
||||
migrate_set_parameter_str(to, "tls-creds", "tlscredsx509server0");
|
||||
|
||||
if (args->authzclient) {
|
||||
rsp = wait_command(to,
|
||||
qtest_qmp_assert_success(to,
|
||||
"{ 'execute': 'object-add',"
|
||||
" 'arguments': { 'qom-type': 'authz-simple',"
|
||||
" 'id': 'tlsauthz0',"
|
||||
|
@ -1410,8 +1395,6 @@ static void test_precopy_common(MigrateCommon *args)
|
|||
return;
|
||||
}
|
||||
|
||||
migrate_ensure_non_converge(from);
|
||||
|
||||
if (args->start_hook) {
|
||||
data_hook = args->start_hook(from, to);
|
||||
}
|
||||
|
@ -1421,6 +1404,31 @@ static void test_precopy_common(MigrateCommon *args)
|
|||
wait_for_serial("src_serial");
|
||||
}
|
||||
|
||||
if (args->live) {
|
||||
/*
|
||||
* Testing live migration, we want to ensure that some
|
||||
* memory is re-dirtied after being transferred, so that
|
||||
* we exercise logic for dirty page handling. We achieve
|
||||
* this with a ridiculosly low bandwidth that guarantees
|
||||
* non-convergance.
|
||||
*/
|
||||
migrate_ensure_non_converge(from);
|
||||
} else {
|
||||
/*
|
||||
* Testing non-live migration, we allow it to run at
|
||||
* full speed to ensure short test case duration.
|
||||
* For tests expected to fail, we don't need to
|
||||
* change anything.
|
||||
*/
|
||||
if (args->result == MIG_TEST_SUCCEED) {
|
||||
qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}");
|
||||
if (!got_src_stop) {
|
||||
qtest_qmp_eventwait(from, "STOP");
|
||||
}
|
||||
migrate_ensure_converge(from);
|
||||
}
|
||||
}
|
||||
|
||||
if (!args->connect_uri) {
|
||||
g_autofree char *local_connect_uri =
|
||||
migrate_get_socket_address(to, "socket-address");
|
||||
|
@ -1438,6 +1446,7 @@ static void test_precopy_common(MigrateCommon *args)
|
|||
qtest_set_expected_status(to, EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
if (args->live) {
|
||||
if (args->iterations) {
|
||||
while (args->iterations--) {
|
||||
wait_for_migration_pass(from);
|
||||
|
@ -1448,15 +1457,30 @@ static void test_precopy_common(MigrateCommon *args)
|
|||
|
||||
migrate_ensure_converge(from);
|
||||
|
||||
/* We do this first, as it has a timeout to stop us
|
||||
* hanging forever if migration didn't converge */
|
||||
/*
|
||||
* We do this first, as it has a timeout to stop us
|
||||
* hanging forever if migration didn't converge
|
||||
*/
|
||||
wait_for_migration_complete(from);
|
||||
|
||||
if (!got_stop) {
|
||||
if (!got_src_stop) {
|
||||
qtest_qmp_eventwait(from, "STOP");
|
||||
}
|
||||
} else {
|
||||
wait_for_migration_complete(from);
|
||||
/*
|
||||
* Must wait for dst to finish reading all incoming
|
||||
* data on the socket before issuing 'cont' otherwise
|
||||
* it'll be ignored
|
||||
*/
|
||||
wait_for_migration_complete(to);
|
||||
|
||||
qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}");
|
||||
}
|
||||
|
||||
if (!got_dst_resume) {
|
||||
qtest_qmp_eventwait(to, "RESUME");
|
||||
}
|
||||
|
||||
wait_for_serial("dest_serial");
|
||||
}
|
||||
|
@ -1474,6 +1498,11 @@ static void test_precopy_unix_plain(void)
|
|||
MigrateCommon args = {
|
||||
.listen_uri = uri,
|
||||
.connect_uri = uri,
|
||||
/*
|
||||
* The simplest use case of precopy, covering smoke tests of
|
||||
* get-dirty-log dirty tracking.
|
||||
*/
|
||||
.live = true,
|
||||
};
|
||||
|
||||
test_precopy_common(&args);
|
||||
|
@ -1489,6 +1518,11 @@ static void test_precopy_unix_dirty_ring(void)
|
|||
},
|
||||
.listen_uri = uri,
|
||||
.connect_uri = uri,
|
||||
/*
|
||||
* Besides the precopy/unix basic test, cover dirty ring interface
|
||||
* rather than get-dirty-log.
|
||||
*/
|
||||
.live = true,
|
||||
};
|
||||
|
||||
test_precopy_common(&args);
|
||||
|
@ -1562,7 +1596,7 @@ static void test_ignore_shared(void)
|
|||
|
||||
wait_for_migration_pass(from);
|
||||
|
||||
if (!got_stop) {
|
||||
if (!got_src_stop) {
|
||||
qtest_qmp_eventwait(from, "STOP");
|
||||
}
|
||||
|
||||
|
@ -1596,10 +1630,13 @@ static void test_precopy_unix_xbzrle(void)
|
|||
MigrateCommon args = {
|
||||
.connect_uri = uri,
|
||||
.listen_uri = uri,
|
||||
|
||||
.start_hook = test_migrate_xbzrle_start,
|
||||
|
||||
.iterations = 2,
|
||||
/*
|
||||
* XBZRLE needs pages to be modified when doing the 2nd+ round
|
||||
* iteration to have real data pushed to the stream.
|
||||
*/
|
||||
.live = true,
|
||||
};
|
||||
|
||||
test_precopy_common(&args);
|
||||
|
@ -1617,6 +1654,12 @@ static void test_precopy_unix_compress(void)
|
|||
* the previous iteration.
|
||||
*/
|
||||
.iterations = 2,
|
||||
/*
|
||||
* We make sure the compressor can always work well even if guest
|
||||
* memory is changing. See commit 34ab9e9743 where we used to fix
|
||||
* a bug when only trigger-able with guest memory changing.
|
||||
*/
|
||||
.live = true,
|
||||
};
|
||||
|
||||
test_precopy_common(&args);
|
||||
|
@ -1634,6 +1677,8 @@ static void test_precopy_unix_compress_nowait(void)
|
|||
* the previous iteration.
|
||||
*/
|
||||
.iterations = 2,
|
||||
/* Same reason for the wait version of precopy compress test */
|
||||
.live = true,
|
||||
};
|
||||
|
||||
test_precopy_common(&args);
|
||||
|
@ -1771,7 +1816,6 @@ static void test_precopy_tcp_tls_x509_reject_anon_client(void)
|
|||
static void *test_migrate_fd_start_hook(QTestState *from,
|
||||
QTestState *to)
|
||||
{
|
||||
QDict *rsp;
|
||||
int ret;
|
||||
int pair[2];
|
||||
|
||||
|
@ -1780,22 +1824,19 @@ static void *test_migrate_fd_start_hook(QTestState *from,
|
|||
g_assert_cmpint(ret, ==, 0);
|
||||
|
||||
/* Send the 1st socket to the target */
|
||||
rsp = wait_command_fd(to, pair[0],
|
||||
qtest_qmp_fds_assert_success(to, &pair[0], 1,
|
||||
"{ 'execute': 'getfd',"
|
||||
" 'arguments': { 'fdname': 'fd-mig' }}");
|
||||
qobject_unref(rsp);
|
||||
close(pair[0]);
|
||||
|
||||
/* Start incoming migration from the 1st socket */
|
||||
rsp = wait_command(to, "{ 'execute': 'migrate-incoming',"
|
||||
qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
|
||||
" 'arguments': { 'uri': 'fd:fd-mig' }}");
|
||||
qobject_unref(rsp);
|
||||
|
||||
/* Send the 2nd socket to the target */
|
||||
rsp = wait_command_fd(from, pair[1],
|
||||
qtest_qmp_fds_assert_success(from, &pair[1], 1,
|
||||
"{ 'execute': 'getfd',"
|
||||
" 'arguments': { 'fdname': 'fd-mig' }}");
|
||||
qobject_unref(rsp);
|
||||
close(pair[1]);
|
||||
|
||||
return NULL;
|
||||
|
@ -1971,7 +2012,7 @@ static void test_migrate_auto_converge(void)
|
|||
break;
|
||||
}
|
||||
usleep(20);
|
||||
g_assert_false(got_stop);
|
||||
g_assert_false(got_src_stop);
|
||||
} while (true);
|
||||
/* The first percentage of throttling should be at least init_pct */
|
||||
g_assert_cmpint(percentage, >=, init_pct);
|
||||
|
@ -2002,8 +2043,6 @@ test_migrate_precopy_tcp_multifd_start_common(QTestState *from,
|
|||
QTestState *to,
|
||||
const char *method)
|
||||
{
|
||||
QDict *rsp;
|
||||
|
||||
migrate_set_parameter_int(from, "multifd-channels", 16);
|
||||
migrate_set_parameter_int(to, "multifd-channels", 16);
|
||||
|
||||
|
@ -2014,9 +2053,8 @@ test_migrate_precopy_tcp_multifd_start_common(QTestState *from,
|
|||
migrate_set_capability(to, "multifd", true);
|
||||
|
||||
/* Start incoming migration from the 1st socket */
|
||||
rsp = wait_command(to, "{ 'execute': 'migrate-incoming',"
|
||||
qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
|
||||
" 'arguments': { 'uri': 'tcp:127.0.0.1:0' }}");
|
||||
qobject_unref(rsp);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2049,6 +2087,12 @@ static void test_multifd_tcp_none(void)
|
|||
MigrateCommon args = {
|
||||
.listen_uri = "defer",
|
||||
.start_hook = test_migrate_precopy_tcp_multifd_start,
|
||||
/*
|
||||
* Multifd is more complicated than most of the features, it
|
||||
* directly takes guest page buffers when sending, make sure
|
||||
* everything will work alright even if guest page is changing.
|
||||
*/
|
||||
.live = true,
|
||||
};
|
||||
test_precopy_common(&args);
|
||||
}
|
||||
|
@ -2247,7 +2291,6 @@ static void test_multifd_tcp_cancel(void)
|
|||
.hide_stderr = true,
|
||||
};
|
||||
QTestState *from, *to, *to2;
|
||||
QDict *rsp;
|
||||
g_autofree char *uri = NULL;
|
||||
|
||||
if (test_migrate_start(&from, &to, "defer", &args)) {
|
||||
|
@ -2263,9 +2306,8 @@ static void test_multifd_tcp_cancel(void)
|
|||
migrate_set_capability(to, "multifd", true);
|
||||
|
||||
/* Start incoming migration from the 1st socket */
|
||||
rsp = wait_command(to, "{ 'execute': 'migrate-incoming',"
|
||||
qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming',"
|
||||
" 'arguments': { 'uri': 'tcp:127.0.0.1:0' }}");
|
||||
qobject_unref(rsp);
|
||||
|
||||
/* Wait for the first serial output from the source */
|
||||
wait_for_serial("src_serial");
|
||||
|
@ -2295,9 +2337,8 @@ static void test_multifd_tcp_cancel(void)
|
|||
migrate_set_capability(to2, "multifd", true);
|
||||
|
||||
/* Start incoming migration from the 1st socket */
|
||||
rsp = wait_command(to2, "{ 'execute': 'migrate-incoming',"
|
||||
qtest_qmp_assert_success(to2, "{ 'execute': 'migrate-incoming',"
|
||||
" 'arguments': { 'uri': 'tcp:127.0.0.1:0' }}");
|
||||
qobject_unref(rsp);
|
||||
|
||||
g_free(uri);
|
||||
uri = migrate_get_socket_address(to2, "socket-address");
|
||||
|
@ -2310,7 +2351,7 @@ static void test_multifd_tcp_cancel(void)
|
|||
|
||||
wait_for_migration_pass(from);
|
||||
|
||||
if (!got_stop) {
|
||||
if (!got_src_stop) {
|
||||
qtest_qmp_eventwait(from, "STOP");
|
||||
}
|
||||
qtest_qmp_eventwait(to2, "RESUME");
|
||||
|
@ -2322,32 +2363,33 @@ static void test_multifd_tcp_cancel(void)
|
|||
|
||||
static void calc_dirty_rate(QTestState *who, uint64_t calc_time)
|
||||
{
|
||||
qobject_unref(qmp_command(who,
|
||||
qtest_qmp_assert_success(who,
|
||||
"{ 'execute': 'calc-dirty-rate',"
|
||||
"'arguments': { "
|
||||
"'calc-time': %" PRIu64 ","
|
||||
"'mode': 'dirty-ring' }}",
|
||||
calc_time));
|
||||
calc_time);
|
||||
}
|
||||
|
||||
static QDict *query_dirty_rate(QTestState *who)
|
||||
{
|
||||
return qmp_command(who, "{ 'execute': 'query-dirty-rate' }");
|
||||
return qtest_qmp_assert_success_ref(who,
|
||||
"{ 'execute': 'query-dirty-rate' }");
|
||||
}
|
||||
|
||||
static void dirtylimit_set_all(QTestState *who, uint64_t dirtyrate)
|
||||
{
|
||||
qobject_unref(qmp_command(who,
|
||||
qtest_qmp_assert_success(who,
|
||||
"{ 'execute': 'set-vcpu-dirty-limit',"
|
||||
"'arguments': { "
|
||||
"'dirty-rate': %" PRIu64 " } }",
|
||||
dirtyrate));
|
||||
dirtyrate);
|
||||
}
|
||||
|
||||
static void cancel_vcpu_dirty_limit(QTestState *who)
|
||||
{
|
||||
qobject_unref(qmp_command(who,
|
||||
"{ 'execute': 'cancel-vcpu-dirty-limit' }"));
|
||||
qtest_qmp_assert_success(who,
|
||||
"{ 'execute': 'cancel-vcpu-dirty-limit' }");
|
||||
}
|
||||
|
||||
static QDict *query_vcpu_dirty_limit(QTestState *who)
|
||||
|
|
Loading…
Reference in a new issue