Migration pull request
- Proper TLS termination for multifd - Fixes for bugs while cancelling migration - Fix for a hang after migration failure (#2633) - Tests for qmp_migrate_cancel - Fix for CID 1590980 - Fixes and improvements to guestperf.py -----BEGIN PGP SIGNATURE----- iQJEBAABCAAuFiEEqhtIsKIjJqWkw2TPx5jcdBvsMZ0FAmevp3oQHGZhcm9zYXNA c3VzZS5kZQAKCRDHmNx0G+wxnSgGD/9z2ATsf073wDupwJ7tJIxgZ6D8Dlb7yPZ6 azRgC7TMv1VGE0cx4r1IiNopFDUodrVO3yXA9D7GVvfkgSr9Oa4oUniQwItM9PT4 QymGPKIE0nuwPCvCrlKXXGruLMngTeb0kpJeseJ9vEXJlQxLvYCtcELF6j2tzVmx nisMgMZiyBwYfS0b7ZctXHqY0+NmNuke/giX6ceUAaj4wqpgFI3zo9OGCHYinYsR oMoMLusyUnDBCqV2P3jGGz4W2KmkCxStnH0yRdUN9mwt0KLl82t6e0aCJqkWo6+W m68DlZgUFwbz4Aq5M2RDPhXvXgim8Ryi29zRuedx8ngYS9Qz6D5y4Fgp4uv/N7ia v8bB6QPZMOkhPq2gkCxPEy47l4tDZhrWRqqEqw4h1nO01KCJ2+y2IZCOBmPFXywT B58f7KvmnLLiYbfWxjnQmOXs9PKRsQjJk96BmRCbf03WeNTF+FHuvQZu9h4Bwb2/ im0kJSq2zR8eSamH2L2dyYhQZ4JqMJa7I3JXqJbAjhk1ya6kX5v899EcktTPDVSG xGINVshpfwwFovRqhgYL9fjqrO8DMNZCbS6IEGLuR5lx90Wo5a8XbKX71JmsnZUO jnGJ+1InTZcbUvp0tkQzXWwUKx8MCP/OWTb098D8oUmfEumYozzsAW5X9kw+4hVJ rpYvw5IYfA== =cBl0 -----END PGP SIGNATURE----- Merge tag 'migration-20250214-pull-request' of https://gitlab.com/farosas/qemu into staging Migration pull request - Proper TLS termination for multifd - Fixes for bugs while cancelling migration - Fix for a hang after migration failure (#2633) - Tests for qmp_migrate_cancel - Fix for CID 1590980 - Fixes and improvements to guestperf.py # -----BEGIN PGP SIGNATURE----- # # iQJEBAABCAAuFiEEqhtIsKIjJqWkw2TPx5jcdBvsMZ0FAmevp3oQHGZhcm9zYXNA # c3VzZS5kZQAKCRDHmNx0G+wxnSgGD/9z2ATsf073wDupwJ7tJIxgZ6D8Dlb7yPZ6 # azRgC7TMv1VGE0cx4r1IiNopFDUodrVO3yXA9D7GVvfkgSr9Oa4oUniQwItM9PT4 # QymGPKIE0nuwPCvCrlKXXGruLMngTeb0kpJeseJ9vEXJlQxLvYCtcELF6j2tzVmx # nisMgMZiyBwYfS0b7ZctXHqY0+NmNuke/giX6ceUAaj4wqpgFI3zo9OGCHYinYsR # oMoMLusyUnDBCqV2P3jGGz4W2KmkCxStnH0yRdUN9mwt0KLl82t6e0aCJqkWo6+W # m68DlZgUFwbz4Aq5M2RDPhXvXgim8Ryi29zRuedx8ngYS9Qz6D5y4Fgp4uv/N7ia # v8bB6QPZMOkhPq2gkCxPEy47l4tDZhrWRqqEqw4h1nO01KCJ2+y2IZCOBmPFXywT # B58f7KvmnLLiYbfWxjnQmOXs9PKRsQjJk96BmRCbf03WeNTF+FHuvQZu9h4Bwb2/ # im0kJSq2zR8eSamH2L2dyYhQZ4JqMJa7I3JXqJbAjhk1ya6kX5v899EcktTPDVSG # xGINVshpfwwFovRqhgYL9fjqrO8DMNZCbS6IEGLuR5lx90Wo5a8XbKX71JmsnZUO # jnGJ+1InTZcbUvp0tkQzXWwUKx8MCP/OWTb098D8oUmfEumYozzsAW5X9kw+4hVJ # rpYvw5IYfA== # =cBl0 # -----END PGP SIGNATURE----- # gpg: Signature made Fri 14 Feb 2025 15:28:42 EST # gpg: using RSA key AA1B48B0A22326A5A4C364CFC798DC741BEC319D # gpg: issuer "farosas@suse.de" # gpg: Good signature from "Fabiano Rosas <farosas@suse.de>" [unknown] # gpg: aka "Fabiano Almeida Rosas <fabiano.rosas@suse.com>" [unknown] # gpg: WARNING: The key's User ID is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: AA1B 48B0 A223 26A5 A4C3 64CF C798 DC74 1BEC 319D * tag 'migration-20250214-pull-request' of https://gitlab.com/farosas/qemu: (22 commits) guestperf: Add test result data into report guestperf: Introduce multifd compression option guestperf: Nitpick the inconsistent parameters guestperf: Support deferred migration for multifd migration: use parameters.mode in cpr_state_save migration: Update migrate_cancel documentation tests/qtest/migration: Add a cancel test tests/qtest/migration: Introduce migration_test_add_suffix migration: Don't set FAILED state when cancelling migration: Reject qmp_migrate_cancel after postcopy migration: Fix hang after error in destination setup phase migration: Change migrate_fd_ to migration_ migration: Unify migration_cancel and migrate_fd_cancel migration: Set migration error outside of migrate_cancel migration: Check migration error after loadvm migration/multifd: Add a compat property for TLS termination migration/multifd: Terminate the TLS connection io: Add a read flag for relaxed EOF io: Add flags argument to qio_channel_readv_full_all_eof crypto: Remove qcrypto_tls_session_get_handshake_status ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
9af3d9a931
@ -546,45 +546,69 @@ qcrypto_tls_session_handshake(QCryptoTLSSession *session,
|
||||
Error **errp)
|
||||
{
|
||||
int ret = gnutls_handshake(session->handle);
|
||||
if (ret == 0) {
|
||||
if (!ret) {
|
||||
session->handshakeComplete = true;
|
||||
} else {
|
||||
if (ret == GNUTLS_E_INTERRUPTED ||
|
||||
ret == GNUTLS_E_AGAIN) {
|
||||
ret = 1;
|
||||
} else {
|
||||
if (session->rerr || session->werr) {
|
||||
error_setg(errp, "TLS handshake failed: %s: %s",
|
||||
gnutls_strerror(ret),
|
||||
error_get_pretty(session->rerr ?
|
||||
session->rerr : session->werr));
|
||||
} else {
|
||||
error_setg(errp, "TLS handshake failed: %s",
|
||||
gnutls_strerror(ret));
|
||||
}
|
||||
ret = -1;
|
||||
}
|
||||
return QCRYPTO_TLS_HANDSHAKE_COMPLETE;
|
||||
}
|
||||
|
||||
if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
|
||||
int direction = gnutls_record_get_direction(session->handle);
|
||||
return direction ? QCRYPTO_TLS_HANDSHAKE_SENDING :
|
||||
QCRYPTO_TLS_HANDSHAKE_RECVING;
|
||||
}
|
||||
|
||||
if (session->rerr || session->werr) {
|
||||
error_setg(errp, "TLS handshake failed: %s: %s",
|
||||
gnutls_strerror(ret),
|
||||
error_get_pretty(session->rerr ?
|
||||
session->rerr : session->werr));
|
||||
} else {
|
||||
error_setg(errp, "TLS handshake failed: %s",
|
||||
gnutls_strerror(ret));
|
||||
}
|
||||
|
||||
error_free(session->rerr);
|
||||
error_free(session->werr);
|
||||
session->rerr = session->werr = NULL;
|
||||
|
||||
return ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
QCryptoTLSSessionHandshakeStatus
|
||||
qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *session)
|
||||
int
|
||||
qcrypto_tls_session_bye(QCryptoTLSSession *session, Error **errp)
|
||||
{
|
||||
if (session->handshakeComplete) {
|
||||
return QCRYPTO_TLS_HANDSHAKE_COMPLETE;
|
||||
} else if (gnutls_record_get_direction(session->handle) == 0) {
|
||||
return QCRYPTO_TLS_HANDSHAKE_RECVING;
|
||||
} else {
|
||||
return QCRYPTO_TLS_HANDSHAKE_SENDING;
|
||||
}
|
||||
}
|
||||
int ret;
|
||||
|
||||
if (!session->handshakeComplete) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = gnutls_bye(session->handle, GNUTLS_SHUT_WR);
|
||||
|
||||
if (!ret) {
|
||||
return QCRYPTO_TLS_BYE_COMPLETE;
|
||||
}
|
||||
|
||||
if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
|
||||
int direction = gnutls_record_get_direction(session->handle);
|
||||
return direction ? QCRYPTO_TLS_BYE_SENDING : QCRYPTO_TLS_BYE_RECVING;
|
||||
}
|
||||
|
||||
if (session->rerr || session->werr) {
|
||||
error_setg(errp, "TLS termination failed: %s: %s", gnutls_strerror(ret),
|
||||
error_get_pretty(session->rerr ?
|
||||
session->rerr : session->werr));
|
||||
} else {
|
||||
error_setg(errp, "TLS termination failed: %s", gnutls_strerror(ret));
|
||||
}
|
||||
|
||||
error_free(session->rerr);
|
||||
error_free(session->werr);
|
||||
session->rerr = session->werr = NULL;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
qcrypto_tls_session_get_key_size(QCryptoTLSSession *session,
|
||||
@ -692,10 +716,10 @@ qcrypto_tls_session_handshake(QCryptoTLSSession *sess,
|
||||
}
|
||||
|
||||
|
||||
QCryptoTLSSessionHandshakeStatus
|
||||
qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *sess)
|
||||
int
|
||||
qcrypto_tls_session_bye(QCryptoTLSSession *session, Error **errp)
|
||||
{
|
||||
return QCRYPTO_TLS_HANDSHAKE_COMPLETE;
|
||||
return QCRYPTO_TLS_BYE_COMPLETE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -42,6 +42,7 @@ GlobalProperty hw_compat_9_2[] = {
|
||||
{ "virtio-balloon-pci-transitional", "vectors", "0" },
|
||||
{ "virtio-balloon-pci-non-transitional", "vectors", "0" },
|
||||
{ "virtio-mem-pci", "vectors", "0" },
|
||||
{ "migration", "multifd-clean-tls-termination", "false" },
|
||||
};
|
||||
const size_t hw_compat_9_2_len = G_N_ELEMENTS(hw_compat_9_2);
|
||||
|
||||
|
@ -110,7 +110,7 @@ static ssize_t mpqemu_read(QIOChannel *ioc, void *buf, size_t len, int **fds,
|
||||
bql_unlock();
|
||||
}
|
||||
|
||||
ret = qio_channel_readv_full_all_eof(ioc, &iov, 1, fds, nfds, errp);
|
||||
ret = qio_channel_readv_full_all_eof(ioc, &iov, 1, fds, nfds, 0, errp);
|
||||
|
||||
if (drop_bql && !iothread && !qemu_in_coroutine()) {
|
||||
bql_lock();
|
||||
|
@ -75,12 +75,14 @@
|
||||
* GINT_TO_POINTER(fd));
|
||||
*
|
||||
* while (1) {
|
||||
* if (qcrypto_tls_session_handshake(sess, errp) < 0) {
|
||||
* int ret = qcrypto_tls_session_handshake(sess, errp);
|
||||
*
|
||||
* if (ret < 0) {
|
||||
* qcrypto_tls_session_free(sess);
|
||||
* return -1;
|
||||
* }
|
||||
*
|
||||
* switch(qcrypto_tls_session_get_handshake_status(sess)) {
|
||||
* switch(ret) {
|
||||
* case QCRYPTO_TLS_HANDSHAKE_COMPLETE:
|
||||
* if (qcrypto_tls_session_check_credentials(sess, errp) < )) {
|
||||
* qcrypto_tls_session_free(sess);
|
||||
@ -170,7 +172,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSSession, qcrypto_tls_session_free)
|
||||
*
|
||||
* Validate the peer's credentials after a successful
|
||||
* TLS handshake. It is an error to call this before
|
||||
* qcrypto_tls_session_get_handshake_status() returns
|
||||
* qcrypto_tls_session_handshake() returns
|
||||
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
|
||||
*
|
||||
* Returns 0 if the credentials validated, -1 on error
|
||||
@ -226,7 +228,7 @@ void qcrypto_tls_session_set_callbacks(QCryptoTLSSession *sess,
|
||||
* registered with qcrypto_tls_session_set_callbacks()
|
||||
*
|
||||
* It is an error to call this before
|
||||
* qcrypto_tls_session_get_handshake_status() returns
|
||||
* qcrypto_tls_session_handshake() returns
|
||||
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
|
||||
*
|
||||
* Returns: the number of bytes sent,
|
||||
@ -256,7 +258,7 @@ ssize_t qcrypto_tls_session_write(QCryptoTLSSession *sess,
|
||||
* opposed to an error.
|
||||
*
|
||||
* It is an error to call this before
|
||||
* qcrypto_tls_session_get_handshake_status() returns
|
||||
* qcrypto_tls_session_handshake() returns
|
||||
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
|
||||
*
|
||||
* Returns: the number of bytes received,
|
||||
@ -289,8 +291,7 @@ size_t qcrypto_tls_session_check_pending(QCryptoTLSSession *sess);
|
||||
* the underlying data channel is non-blocking, then
|
||||
* this method may return control before the handshake
|
||||
* is complete. On non-blocking channels the
|
||||
* qcrypto_tls_session_get_handshake_status() method
|
||||
* should be used to determine whether the handshake
|
||||
* return value determines whether the handshake
|
||||
* has completed, or is waiting to send or receive
|
||||
* data. In the latter cases, the caller should setup
|
||||
* an event loop watch and call this method again
|
||||
@ -306,22 +307,27 @@ typedef enum {
|
||||
QCRYPTO_TLS_HANDSHAKE_RECVING,
|
||||
} QCryptoTLSSessionHandshakeStatus;
|
||||
|
||||
typedef enum {
|
||||
QCRYPTO_TLS_BYE_COMPLETE,
|
||||
QCRYPTO_TLS_BYE_SENDING,
|
||||
QCRYPTO_TLS_BYE_RECVING,
|
||||
} QCryptoTLSSessionByeStatus;
|
||||
|
||||
/**
|
||||
* qcrypto_tls_session_get_handshake_status:
|
||||
* @sess: the TLS session object
|
||||
* qcrypto_tls_session_bye:
|
||||
* @session: the TLS session object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Check the status of the TLS handshake. This
|
||||
* is used with non-blocking data channels to
|
||||
* determine whether the handshake is waiting
|
||||
* to send or receive further data to/from the
|
||||
* remote peer.
|
||||
*
|
||||
* Once this returns QCRYPTO_TLS_HANDSHAKE_COMPLETE
|
||||
* it is permitted to send/receive payload data on
|
||||
* the channel
|
||||
* Start, or continue, a TLS termination sequence. If the underlying
|
||||
* data channel is non-blocking, then this method may return control
|
||||
* before the termination is complete. The return value will indicate
|
||||
* whether the termination has completed, or is waiting to send or
|
||||
* receive data. In the latter cases, the caller should setup an event
|
||||
* loop watch and call this method again once the underlying data
|
||||
* channel is ready to read or write again.
|
||||
*/
|
||||
QCryptoTLSSessionHandshakeStatus
|
||||
qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *sess);
|
||||
int
|
||||
qcrypto_tls_session_bye(QCryptoTLSSession *session, Error **errp);
|
||||
|
||||
/**
|
||||
* qcrypto_tls_session_get_key_size:
|
||||
|
@ -49,8 +49,20 @@ struct QIOChannelTLS {
|
||||
QCryptoTLSSession *session;
|
||||
QIOChannelShutdown shutdown;
|
||||
guint hs_ioc_tag;
|
||||
guint bye_ioc_tag;
|
||||
};
|
||||
|
||||
/**
|
||||
* qio_channel_tls_bye:
|
||||
* @ioc: the TLS channel object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Perform the TLS session termination. This method will return
|
||||
* immediately and the termination will continue in the background,
|
||||
* provided the main loop is running.
|
||||
*/
|
||||
void qio_channel_tls_bye(QIOChannelTLS *ioc, Error **errp);
|
||||
|
||||
/**
|
||||
* qio_channel_tls_new_server:
|
||||
* @master: the underlying channel object
|
||||
|
@ -35,6 +35,7 @@ OBJECT_DECLARE_TYPE(QIOChannel, QIOChannelClass,
|
||||
#define QIO_CHANNEL_WRITE_FLAG_ZERO_COPY 0x1
|
||||
|
||||
#define QIO_CHANNEL_READ_FLAG_MSG_PEEK 0x1
|
||||
#define QIO_CHANNEL_READ_FLAG_RELAXED_EOF 0x2
|
||||
|
||||
typedef enum QIOChannelFeature QIOChannelFeature;
|
||||
|
||||
@ -885,6 +886,7 @@ void qio_channel_set_aio_fd_handler(QIOChannel *ioc,
|
||||
* @niov: the length of the @iov array
|
||||
* @fds: an array of file handles to read
|
||||
* @nfds: number of file handles in @fds
|
||||
* @flags: read flags (QIO_CHANNEL_READ_FLAG_*)
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
*
|
||||
@ -903,6 +905,7 @@ int coroutine_mixed_fn qio_channel_readv_full_all_eof(QIOChannel *ioc,
|
||||
const struct iovec *iov,
|
||||
size_t niov,
|
||||
int **fds, size_t *nfds,
|
||||
int flags,
|
||||
Error **errp);
|
||||
|
||||
/**
|
||||
|
@ -162,16 +162,17 @@ static void qio_channel_tls_handshake_task(QIOChannelTLS *ioc,
|
||||
GMainContext *context)
|
||||
{
|
||||
Error *err = NULL;
|
||||
QCryptoTLSSessionHandshakeStatus status;
|
||||
int status;
|
||||
|
||||
if (qcrypto_tls_session_handshake(ioc->session, &err) < 0) {
|
||||
status = qcrypto_tls_session_handshake(ioc->session, &err);
|
||||
|
||||
if (status < 0) {
|
||||
trace_qio_channel_tls_handshake_fail(ioc);
|
||||
qio_task_set_error(task, err);
|
||||
qio_task_complete(task);
|
||||
return;
|
||||
}
|
||||
|
||||
status = qcrypto_tls_session_get_handshake_status(ioc->session);
|
||||
if (status == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
|
||||
trace_qio_channel_tls_handshake_complete(ioc);
|
||||
if (qcrypto_tls_session_check_credentials(ioc->session,
|
||||
@ -247,6 +248,85 @@ void qio_channel_tls_handshake(QIOChannelTLS *ioc,
|
||||
qio_channel_tls_handshake_task(ioc, task, context);
|
||||
}
|
||||
|
||||
static gboolean qio_channel_tls_bye_io(QIOChannel *ioc, GIOCondition condition,
|
||||
gpointer user_data);
|
||||
|
||||
static void qio_channel_tls_bye_task(QIOChannelTLS *ioc, QIOTask *task,
|
||||
GMainContext *context)
|
||||
{
|
||||
GIOCondition condition;
|
||||
QIOChannelTLSData *data;
|
||||
int status;
|
||||
Error *err = NULL;
|
||||
|
||||
status = qcrypto_tls_session_bye(ioc->session, &err);
|
||||
|
||||
if (status < 0) {
|
||||
trace_qio_channel_tls_bye_fail(ioc);
|
||||
qio_task_set_error(task, err);
|
||||
qio_task_complete(task);
|
||||
return;
|
||||
}
|
||||
|
||||
if (status == QCRYPTO_TLS_BYE_COMPLETE) {
|
||||
qio_task_complete(task);
|
||||
return;
|
||||
}
|
||||
|
||||
data = g_new0(typeof(*data), 1);
|
||||
data->task = task;
|
||||
data->context = context;
|
||||
|
||||
if (context) {
|
||||
g_main_context_ref(context);
|
||||
}
|
||||
|
||||
if (status == QCRYPTO_TLS_BYE_SENDING) {
|
||||
condition = G_IO_OUT;
|
||||
} else {
|
||||
condition = G_IO_IN;
|
||||
}
|
||||
|
||||
trace_qio_channel_tls_bye_pending(ioc, status);
|
||||
ioc->bye_ioc_tag = qio_channel_add_watch_full(ioc->master, condition,
|
||||
qio_channel_tls_bye_io,
|
||||
data, NULL, context);
|
||||
}
|
||||
|
||||
|
||||
static gboolean qio_channel_tls_bye_io(QIOChannel *ioc, GIOCondition condition,
|
||||
gpointer user_data)
|
||||
{
|
||||
QIOChannelTLSData *data = user_data;
|
||||
QIOTask *task = data->task;
|
||||
GMainContext *context = data->context;
|
||||
QIOChannelTLS *tioc = QIO_CHANNEL_TLS(qio_task_get_source(task));
|
||||
|
||||
tioc->bye_ioc_tag = 0;
|
||||
g_free(data);
|
||||
qio_channel_tls_bye_task(tioc, task, context);
|
||||
|
||||
if (context) {
|
||||
g_main_context_unref(context);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void propagate_error(QIOTask *task, gpointer opaque)
|
||||
{
|
||||
qio_task_propagate_error(task, opaque);
|
||||
}
|
||||
|
||||
void qio_channel_tls_bye(QIOChannelTLS *ioc, Error **errp)
|
||||
{
|
||||
QIOTask *task;
|
||||
|
||||
task = qio_task_new(OBJECT(ioc), propagate_error, errp, NULL);
|
||||
|
||||
trace_qio_channel_tls_bye_start(ioc);
|
||||
qio_channel_tls_bye_task(ioc, task, NULL);
|
||||
}
|
||||
|
||||
static void qio_channel_tls_init(Object *obj G_GNUC_UNUSED)
|
||||
{
|
||||
@ -279,6 +359,7 @@ static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
|
||||
tioc->session,
|
||||
iov[i].iov_base,
|
||||
iov[i].iov_len,
|
||||
flags & QIO_CHANNEL_READ_FLAG_RELAXED_EOF ||
|
||||
qatomic_load_acquire(&tioc->shutdown) & QIO_CHANNEL_SHUTDOWN_READ,
|
||||
errp);
|
||||
if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
|
||||
@ -379,6 +460,11 @@ static int qio_channel_tls_close(QIOChannel *ioc,
|
||||
g_clear_handle_id(&tioc->hs_ioc_tag, g_source_remove);
|
||||
}
|
||||
|
||||
if (tioc->bye_ioc_tag) {
|
||||
trace_qio_channel_tls_bye_cancel(ioc);
|
||||
g_clear_handle_id(&tioc->bye_ioc_tag, g_source_remove);
|
||||
}
|
||||
|
||||
return qio_channel_close(tioc->master, errp);
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,8 @@ int coroutine_mixed_fn qio_channel_readv_all_eof(QIOChannel *ioc,
|
||||
size_t niov,
|
||||
Error **errp)
|
||||
{
|
||||
return qio_channel_readv_full_all_eof(ioc, iov, niov, NULL, NULL, errp);
|
||||
return qio_channel_readv_full_all_eof(ioc, iov, niov, NULL, NULL, 0,
|
||||
errp);
|
||||
}
|
||||
|
||||
int coroutine_mixed_fn qio_channel_readv_all(QIOChannel *ioc,
|
||||
@ -130,6 +131,7 @@ int coroutine_mixed_fn qio_channel_readv_full_all_eof(QIOChannel *ioc,
|
||||
const struct iovec *iov,
|
||||
size_t niov,
|
||||
int **fds, size_t *nfds,
|
||||
int flags,
|
||||
Error **errp)
|
||||
{
|
||||
int ret = -1;
|
||||
@ -155,7 +157,7 @@ int coroutine_mixed_fn qio_channel_readv_full_all_eof(QIOChannel *ioc,
|
||||
while ((nlocal_iov > 0) || local_fds) {
|
||||
ssize_t len;
|
||||
len = qio_channel_readv_full(ioc, local_iov, nlocal_iov, local_fds,
|
||||
local_nfds, 0, errp);
|
||||
local_nfds, flags, errp);
|
||||
if (len == QIO_CHANNEL_ERR_BLOCK) {
|
||||
if (qemu_in_coroutine()) {
|
||||
qio_channel_yield(ioc, G_IO_IN);
|
||||
@ -222,7 +224,8 @@ int coroutine_mixed_fn qio_channel_readv_full_all(QIOChannel *ioc,
|
||||
int **fds, size_t *nfds,
|
||||
Error **errp)
|
||||
{
|
||||
int ret = qio_channel_readv_full_all_eof(ioc, iov, niov, fds, nfds, errp);
|
||||
int ret = qio_channel_readv_full_all_eof(ioc, iov, niov, fds, nfds, 0,
|
||||
errp);
|
||||
|
||||
if (ret == 0) {
|
||||
error_setg(errp, "Unexpected end-of-file before all data were read");
|
||||
|
@ -44,6 +44,11 @@ qio_channel_tls_handshake_pending(void *ioc, int status) "TLS handshake pending
|
||||
qio_channel_tls_handshake_fail(void *ioc) "TLS handshake fail ioc=%p"
|
||||
qio_channel_tls_handshake_complete(void *ioc) "TLS handshake complete ioc=%p"
|
||||
qio_channel_tls_handshake_cancel(void *ioc) "TLS handshake cancel ioc=%p"
|
||||
qio_channel_tls_bye_start(void *ioc) "TLS termination start ioc=%p"
|
||||
qio_channel_tls_bye_pending(void *ioc, int status) "TLS termination pending ioc=%p status=%d"
|
||||
qio_channel_tls_bye_fail(void *ioc) "TLS termination fail ioc=%p"
|
||||
qio_channel_tls_bye_complete(void *ioc) "TLS termination complete ioc=%p"
|
||||
qio_channel_tls_bye_cancel(void *ioc) "TLS termination cancel ioc=%p"
|
||||
qio_channel_tls_credentials_allow(void *ioc) "TLS credentials allow ioc=%p"
|
||||
qio_channel_tls_credentials_deny(void *ioc) "TLS credentials deny ioc=%p"
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
void migration_channel_process_incoming(QIOChannel *ioc)
|
||||
{
|
||||
MigrationState *s = migrate_get_current();
|
||||
MigrationIncomingState *mis = migration_incoming_get_current();
|
||||
Error *local_err = NULL;
|
||||
|
||||
trace_migration_set_incoming_channel(
|
||||
@ -47,6 +48,10 @@ void migration_channel_process_incoming(QIOChannel *ioc)
|
||||
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED);
|
||||
if (mis->exit_on_error) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +79,7 @@ void migration_channel_connect(MigrationState *s,
|
||||
if (!error) {
|
||||
/* tls_channel_connect will call back to this
|
||||
* function after the TLS handshake,
|
||||
* so we mustn't call migrate_fd_connect until then
|
||||
* so we mustn't call migration_connect until then
|
||||
*/
|
||||
|
||||
return;
|
||||
@ -89,7 +94,7 @@ void migration_channel_connect(MigrationState *s,
|
||||
qemu_mutex_unlock(&s->qemu_file_lock);
|
||||
}
|
||||
}
|
||||
migrate_fd_connect(s, error);
|
||||
migration_connect(s, error);
|
||||
error_free(error);
|
||||
}
|
||||
|
||||
|
@ -137,6 +137,7 @@ int cpr_state_save(MigrationChannel *channel, Error **errp)
|
||||
trace_cpr_state_save(MigMode_str(mode));
|
||||
|
||||
if (mode == MIG_MODE_CPR_TRANSFER) {
|
||||
g_assert(channel);
|
||||
f = cpr_transfer_output(channel, errp);
|
||||
} else {
|
||||
return 0;
|
||||
|
@ -106,7 +106,6 @@ static GSList *migration_blockers[MIG_MODE__MAX];
|
||||
|
||||
static bool migration_object_check(MigrationState *ms, Error **errp);
|
||||
static bool migration_switchover_start(MigrationState *s, Error **errp);
|
||||
static void migrate_fd_cancel(MigrationState *s);
|
||||
static bool close_return_path_on_source(MigrationState *s);
|
||||
static void migration_completion_end(MigrationState *s);
|
||||
static void migrate_hup_delete(MigrationState *s);
|
||||
@ -342,17 +341,6 @@ void migration_bh_schedule(QEMUBHFunc *cb, void *opaque)
|
||||
qemu_bh_schedule(bh);
|
||||
}
|
||||
|
||||
void migration_cancel(const Error *error)
|
||||
{
|
||||
if (error) {
|
||||
migrate_set_error(current_migration, error);
|
||||
}
|
||||
if (migrate_dirty_limit()) {
|
||||
qmp_cancel_vcpu_dirty_limit(false, -1, NULL);
|
||||
}
|
||||
migrate_fd_cancel(current_migration);
|
||||
}
|
||||
|
||||
void migration_shutdown(void)
|
||||
{
|
||||
/*
|
||||
@ -365,7 +353,7 @@ void migration_shutdown(void)
|
||||
* Cancel the current migration - that will (eventually)
|
||||
* stop the migration using this structure
|
||||
*/
|
||||
migration_cancel(NULL);
|
||||
migration_cancel();
|
||||
object_unref(OBJECT(current_migration));
|
||||
|
||||
/*
|
||||
@ -1435,12 +1423,12 @@ static void migration_cleanup_json_writer(MigrationState *s)
|
||||
g_clear_pointer(&s->vmdesc, json_writer_free);
|
||||
}
|
||||
|
||||
static void migrate_fd_cleanup(MigrationState *s)
|
||||
static void migration_cleanup(MigrationState *s)
|
||||
{
|
||||
MigrationEventType type;
|
||||
QEMUFile *tmp = NULL;
|
||||
|
||||
trace_migrate_fd_cleanup();
|
||||
trace_migration_cleanup();
|
||||
|
||||
migration_cleanup_json_writer(s);
|
||||
|
||||
@ -1497,9 +1485,9 @@ static void migrate_fd_cleanup(MigrationState *s)
|
||||
yank_unregister_instance(MIGRATION_YANK_INSTANCE);
|
||||
}
|
||||
|
||||
static void migrate_fd_cleanup_bh(void *opaque)
|
||||
static void migration_cleanup_bh(void *opaque)
|
||||
{
|
||||
migrate_fd_cleanup(opaque);
|
||||
migration_cleanup(opaque);
|
||||
}
|
||||
|
||||
void migrate_set_error(MigrationState *s, const Error *error)
|
||||
@ -1529,7 +1517,7 @@ static void migrate_error_free(MigrationState *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void migrate_fd_error(MigrationState *s, const Error *error)
|
||||
static void migration_connect_set_error(MigrationState *s, const Error *error)
|
||||
{
|
||||
MigrationStatus current = s->state;
|
||||
MigrationStatus next;
|
||||
@ -1558,12 +1546,17 @@ static void migrate_fd_error(MigrationState *s, const Error *error)
|
||||
migrate_set_error(s, error);
|
||||
}
|
||||
|
||||
static void migrate_fd_cancel(MigrationState *s)
|
||||
void migration_cancel(void)
|
||||
{
|
||||
MigrationState *s = migrate_get_current();
|
||||
int old_state ;
|
||||
bool setup = (s->state == MIGRATION_STATUS_SETUP);
|
||||
|
||||
trace_migrate_fd_cancel();
|
||||
trace_migration_cancel();
|
||||
|
||||
if (migrate_dirty_limit()) {
|
||||
qmp_cancel_vcpu_dirty_limit(false, -1, NULL);
|
||||
}
|
||||
|
||||
WITH_QEMU_LOCK_GUARD(&s->qemu_file_lock) {
|
||||
if (s->rp_state.from_dst_file) {
|
||||
@ -2205,7 +2198,7 @@ void qmp_migrate(const char *uri, bool has_channels,
|
||||
|
||||
out:
|
||||
if (local_err) {
|
||||
migrate_fd_error(s, local_err);
|
||||
migration_connect_set_error(s, local_err);
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
}
|
||||
@ -2250,7 +2243,7 @@ static void qmp_migrate_finish(MigrationAddress *addr, bool resume_requested,
|
||||
if (!resume_requested) {
|
||||
yank_unregister_instance(MIGRATION_YANK_INSTANCE);
|
||||
}
|
||||
migrate_fd_error(s, local_err);
|
||||
migration_connect_set_error(s, local_err);
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
@ -2258,7 +2251,18 @@ static void qmp_migrate_finish(MigrationAddress *addr, bool resume_requested,
|
||||
|
||||
void qmp_migrate_cancel(Error **errp)
|
||||
{
|
||||
migration_cancel(NULL);
|
||||
/*
|
||||
* After postcopy migration has started, the source machine is not
|
||||
* recoverable in case of a migration error. This also means the
|
||||
* cancel command cannot be used as cancel should allow the
|
||||
* machine to continue operation.
|
||||
*/
|
||||
if (migration_in_postcopy()) {
|
||||
error_setg(errp, "Postcopy migration in progress, cannot cancel.");
|
||||
return;
|
||||
}
|
||||
|
||||
migration_cancel();
|
||||
}
|
||||
|
||||
void qmp_migrate_continue(MigrationStatus state, Error **errp)
|
||||
@ -2644,7 +2648,10 @@ static int postcopy_start(MigrationState *ms, Error **errp)
|
||||
if (migrate_postcopy_preempt()) {
|
||||
migration_wait_main_channel(ms);
|
||||
if (postcopy_preempt_establish_channel(ms)) {
|
||||
migrate_set_state(&ms->state, ms->state, MIGRATION_STATUS_FAILED);
|
||||
if (ms->state != MIGRATION_STATUS_CANCELLING) {
|
||||
migrate_set_state(&ms->state, ms->state,
|
||||
MIGRATION_STATUS_FAILED);
|
||||
}
|
||||
error_setg(errp, "%s: Failed to establish preempt channel",
|
||||
__func__);
|
||||
return -1;
|
||||
@ -2982,7 +2989,9 @@ fail:
|
||||
error_free(local_err);
|
||||
}
|
||||
|
||||
migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED);
|
||||
if (s->state != MIGRATION_STATUS_CANCELLING) {
|
||||
migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3005,7 +3014,7 @@ static void bg_migration_completion(MigrationState *s)
|
||||
qemu_put_buffer(s->to_dst_file, s->bioc->data, s->bioc->usage);
|
||||
qemu_fflush(s->to_dst_file);
|
||||
} else if (s->state == MIGRATION_STATUS_CANCELLING) {
|
||||
goto fail;
|
||||
return;
|
||||
}
|
||||
|
||||
if (qemu_file_get_error(s->to_dst_file)) {
|
||||
@ -3434,7 +3443,7 @@ static void migration_iteration_finish(MigrationState *s)
|
||||
break;
|
||||
}
|
||||
|
||||
migration_bh_schedule(migrate_fd_cleanup_bh, s);
|
||||
migration_bh_schedule(migration_cleanup_bh, s);
|
||||
bql_unlock();
|
||||
}
|
||||
|
||||
@ -3462,7 +3471,7 @@ static void bg_migration_iteration_finish(MigrationState *s)
|
||||
break;
|
||||
}
|
||||
|
||||
migration_bh_schedule(migrate_fd_cleanup_bh, s);
|
||||
migration_bh_schedule(migration_cleanup_bh, s);
|
||||
bql_unlock();
|
||||
}
|
||||
|
||||
@ -3844,7 +3853,7 @@ fail_setup:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void migrate_fd_connect(MigrationState *s, Error *error_in)
|
||||
void migration_connect(MigrationState *s, Error *error_in)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
uint64_t rate_limit;
|
||||
@ -3854,24 +3863,24 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
|
||||
/*
|
||||
* If there's a previous error, free it and prepare for another one.
|
||||
* Meanwhile if migration completes successfully, there won't have an error
|
||||
* dumped when calling migrate_fd_cleanup().
|
||||
* dumped when calling migration_cleanup().
|
||||
*/
|
||||
migrate_error_free(s);
|
||||
|
||||
s->expected_downtime = migrate_downtime_limit();
|
||||
if (error_in) {
|
||||
migrate_fd_error(s, error_in);
|
||||
migration_connect_set_error(s, error_in);
|
||||
if (resume) {
|
||||
/*
|
||||
* Don't do cleanup for resume if channel is invalid, but only dump
|
||||
* the error. We wait for another channel connect from the user.
|
||||
* The error_report still gives HMP user a hint on what failed.
|
||||
* It's normally done in migrate_fd_cleanup(), but call it here
|
||||
* It's normally done in migration_cleanup(), but call it here
|
||||
* explicitly.
|
||||
*/
|
||||
error_report_err(error_copy(s->error));
|
||||
} else {
|
||||
migrate_fd_cleanup(s);
|
||||
migration_cleanup(s);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -3949,9 +3958,11 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
|
||||
|
||||
fail:
|
||||
migrate_set_error(s, local_err);
|
||||
migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED);
|
||||
if (s->state != MIGRATION_STATUS_CANCELLING) {
|
||||
migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED);
|
||||
}
|
||||
error_report_err(local_err);
|
||||
migrate_fd_cleanup(s);
|
||||
migration_cleanup(s);
|
||||
}
|
||||
|
||||
static void migration_class_init(ObjectClass *klass, void *data)
|
||||
|
@ -443,6 +443,39 @@ struct MigrationState {
|
||||
* Default value is false. (since 8.1)
|
||||
*/
|
||||
bool multifd_flush_after_each_section;
|
||||
|
||||
/*
|
||||
* This variable only makes sense when set on the machine that is
|
||||
* the destination of a multifd migration with TLS enabled. It
|
||||
* affects the behavior of the last send->recv iteration with
|
||||
* regards to termination of the TLS session.
|
||||
*
|
||||
* When set:
|
||||
*
|
||||
* - the destination QEMU instance can expect to never get a
|
||||
* GNUTLS_E_PREMATURE_TERMINATION error. Manifested as the error
|
||||
* message: "The TLS connection was non-properly terminated".
|
||||
*
|
||||
* When clear:
|
||||
*
|
||||
* - the destination QEMU instance can expect to see a
|
||||
* GNUTLS_E_PREMATURE_TERMINATION error in any multifd channel
|
||||
* whenever the last recv() call of that channel happens after
|
||||
* the source QEMU instance has already issued shutdown() on the
|
||||
* channel.
|
||||
*
|
||||
* Commit 637280aeb2 (since 9.1) introduced a side effect that
|
||||
* causes the destination instance to not be affected by the
|
||||
* premature termination, while commit 1d457daf86 (since 10.0)
|
||||
* causes the premature termination condition to be once again
|
||||
* reachable.
|
||||
*
|
||||
* NOTE: Regardless of the state of this option, a premature
|
||||
* termination of the TLS connection might happen due to error at
|
||||
* any moment prior to the last send->recv iteration.
|
||||
*/
|
||||
bool multifd_clean_tls_termination;
|
||||
|
||||
/*
|
||||
* This decides the size of guest memory chunk that will be used
|
||||
* to track dirty bitmap clearing. The size of memory chunk will
|
||||
@ -484,7 +517,7 @@ bool migration_has_all_channels(void);
|
||||
void migrate_set_error(MigrationState *s, const Error *error);
|
||||
bool migrate_has_error(MigrationState *s);
|
||||
|
||||
void migrate_fd_connect(MigrationState *s, Error *error_in);
|
||||
void migration_connect(MigrationState *s, Error *error_in);
|
||||
|
||||
int migration_call_notifiers(MigrationState *s, MigrationEventType type,
|
||||
Error **errp);
|
||||
@ -530,7 +563,7 @@ void migration_make_urgent_request(void);
|
||||
void migration_consume_urgent_request(void);
|
||||
bool migration_rate_limit(void);
|
||||
void migration_bh_schedule(QEMUBHFunc *cb, void *opaque);
|
||||
void migration_cancel(const Error *error);
|
||||
void migration_cancel(void);
|
||||
|
||||
void migration_populate_vfio_info(MigrationInfo *info);
|
||||
void migration_reset_vfio_bytes_transferred(void);
|
||||
|
@ -444,7 +444,7 @@ static bool multifd_send_cleanup_channel(MultiFDSendParams *p, Error **errp)
|
||||
* channels have no I/O handler callback registered when reaching
|
||||
* here, because migration thread will wait for all multifd channel
|
||||
* establishments to complete during setup. Since
|
||||
* migrate_fd_cleanup() will be scheduled in main thread too, all
|
||||
* migration_cleanup() will be scheduled in main thread too, all
|
||||
* previous callbacks should guarantee to be completed when
|
||||
* reaching here. See multifd_send_state.channels_created and its
|
||||
* usage. In the future, we could replace this with an assert
|
||||
@ -490,6 +490,36 @@ void multifd_send_shutdown(void)
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < migrate_multifd_channels(); i++) {
|
||||
MultiFDSendParams *p = &multifd_send_state->params[i];
|
||||
|
||||
/* thread_created implies the TLS handshake has succeeded */
|
||||
if (p->tls_thread_created && p->thread_created) {
|
||||
Error *local_err = NULL;
|
||||
/*
|
||||
* The destination expects the TLS session to always be
|
||||
* properly terminated. This helps to detect a premature
|
||||
* termination in the middle of the stream. Note that
|
||||
* older QEMUs always break the connection on the source
|
||||
* and the destination always sees
|
||||
* GNUTLS_E_PREMATURE_TERMINATION.
|
||||
*/
|
||||
migration_tls_channel_end(p->c, &local_err);
|
||||
|
||||
/*
|
||||
* The above can return an error in case the migration has
|
||||
* already failed. If the migration succeeded, errors are
|
||||
* not expected but there's no need to kill the source.
|
||||
*/
|
||||
if (local_err && !migration_has_failed(migrate_get_current())) {
|
||||
warn_report(
|
||||
"multifd_send_%d: Failed to terminate TLS connection: %s",
|
||||
p->id, error_get_pretty(local_err));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
multifd_send_terminate_threads();
|
||||
|
||||
for (i = 0; i < migrate_multifd_channels(); i++) {
|
||||
@ -1121,6 +1151,7 @@ void multifd_recv_sync_main(void)
|
||||
|
||||
static void *multifd_recv_thread(void *opaque)
|
||||
{
|
||||
MigrationState *s = migrate_get_current();
|
||||
MultiFDRecvParams *p = opaque;
|
||||
Error *local_err = NULL;
|
||||
bool use_packets = multifd_use_packets();
|
||||
@ -1129,19 +1160,34 @@ static void *multifd_recv_thread(void *opaque)
|
||||
trace_multifd_recv_thread_start(p->id);
|
||||
rcu_register_thread();
|
||||
|
||||
if (!s->multifd_clean_tls_termination) {
|
||||
p->read_flags = QIO_CHANNEL_READ_FLAG_RELAXED_EOF;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
uint32_t flags = 0;
|
||||
bool has_data = false;
|
||||
p->normal_num = 0;
|
||||
|
||||
if (use_packets) {
|
||||
struct iovec iov = {
|
||||
.iov_base = (void *)p->packet,
|
||||
.iov_len = p->packet_len
|
||||
};
|
||||
|
||||
if (multifd_recv_should_exit()) {
|
||||
break;
|
||||
}
|
||||
|
||||
ret = qio_channel_read_all_eof(p->c, (void *)p->packet,
|
||||
p->packet_len, &local_err);
|
||||
if (ret == 0 || ret == -1) { /* 0: EOF -1: Error */
|
||||
ret = qio_channel_readv_full_all_eof(p->c, &iov, 1, NULL, NULL,
|
||||
p->read_flags, &local_err);
|
||||
if (!ret) {
|
||||
/* EOF */
|
||||
assert(!local_err);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -244,6 +244,8 @@ typedef struct {
|
||||
uint32_t zero_num;
|
||||
/* used for de-compression methods */
|
||||
void *compress_data;
|
||||
/* Flags for the QIOChannel */
|
||||
int read_flags;
|
||||
} MultiFDRecvParams;
|
||||
|
||||
typedef struct {
|
||||
|
@ -99,6 +99,8 @@ const Property migration_properties[] = {
|
||||
clear_bitmap_shift, CLEAR_BITMAP_SHIFT_DEFAULT),
|
||||
DEFINE_PROP_BOOL("x-preempt-pre-7-2", MigrationState,
|
||||
preempt_pre_7_2, false),
|
||||
DEFINE_PROP_BOOL("multifd-clean-tls-termination", MigrationState,
|
||||
multifd_clean_tls_termination, true),
|
||||
|
||||
/* Migration parameters */
|
||||
DEFINE_PROP_UINT8("x-throttle-trigger-threshold", MigrationState,
|
||||
|
@ -4465,8 +4465,10 @@ static void ram_mig_ram_block_resized(RAMBlockNotifier *n, void *host,
|
||||
* Abort and indicate a proper reason.
|
||||
*/
|
||||
error_setg(&err, "RAM block '%s' resized during precopy.", rb->idstr);
|
||||
migration_cancel(err);
|
||||
migrate_set_error(migrate_get_current(), err);
|
||||
error_free(err);
|
||||
|
||||
migration_cancel();
|
||||
}
|
||||
|
||||
switch (ps) {
|
||||
|
@ -4174,7 +4174,7 @@ void rdma_start_outgoing_migration(void *opaque,
|
||||
|
||||
s->to_dst_file = rdma_new_output(rdma);
|
||||
s->rdma_migration = true;
|
||||
migrate_fd_connect(s, NULL);
|
||||
migration_connect(s, NULL);
|
||||
return;
|
||||
return_path_err:
|
||||
qemu_rdma_cleanup(rdma);
|
||||
|
@ -2940,7 +2940,11 @@ int qemu_loadvm_state(QEMUFile *f)
|
||||
|
||||
/* When reaching here, it must be precopy */
|
||||
if (ret == 0) {
|
||||
ret = qemu_file_get_error(f);
|
||||
if (migrate_has_error(migrate_get_current())) {
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
ret = qemu_file_get_error(f);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -156,6 +156,11 @@ void migration_tls_channel_connect(MigrationState *s,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void migration_tls_channel_end(QIOChannel *ioc, Error **errp)
|
||||
{
|
||||
qio_channel_tls_bye(QIO_CHANNEL_TLS(ioc), errp);
|
||||
}
|
||||
|
||||
bool migrate_channel_requires_tls_upgrade(QIOChannel *ioc)
|
||||
{
|
||||
if (!migrate_tls()) {
|
||||
|
@ -36,7 +36,7 @@ void migration_tls_channel_connect(MigrationState *s,
|
||||
QIOChannel *ioc,
|
||||
const char *hostname,
|
||||
Error **errp);
|
||||
|
||||
void migration_tls_channel_end(QIOChannel *ioc, Error **errp);
|
||||
/* Whether the QIO channel requires further TLS handshake? */
|
||||
bool migrate_channel_requires_tls_upgrade(QIOChannel *ioc);
|
||||
|
||||
|
@ -154,9 +154,9 @@ multifd_set_outgoing_channel(void *ioc, const char *ioctype, const char *hostnam
|
||||
|
||||
# migration.c
|
||||
migrate_set_state(const char *new_state) "new state %s"
|
||||
migrate_fd_cleanup(void) ""
|
||||
migration_cleanup(void) ""
|
||||
migrate_error(const char *error_desc) "error=%s"
|
||||
migrate_fd_cancel(void) ""
|
||||
migration_cancel(void) ""
|
||||
migrate_handle_rp_req_pages(const char *rbname, size_t start, size_t len) "in %s at 0x%zx len 0x%zx"
|
||||
migrate_pending_exact(uint64_t size, uint64_t pre, uint64_t post) "exact pending size %" PRIu64 " (pre = %" PRIu64 " post=%" PRIu64 ")"
|
||||
migrate_pending_estimate(uint64_t size, uint64_t pre, uint64_t post) "estimate pending size %" PRIu64 " (pre = %" PRIu64 " post=%" PRIu64 ")"
|
||||
|
@ -1524,7 +1524,9 @@
|
||||
##
|
||||
# @migrate_cancel:
|
||||
#
|
||||
# Cancel the current executing migration process.
|
||||
# Cancel the currently executing migration process. Allows a new
|
||||
# migration to be started right after. When postcopy-ram is in use,
|
||||
# cancelling is not allowed after the postcopy phase has started.
|
||||
#
|
||||
# .. note:: This command succeeds even if there is no migration
|
||||
# process running.
|
||||
|
@ -127,7 +127,7 @@ COMPARISONS = [
|
||||
# varying numbers of channels
|
||||
Comparison("compr-multifd", scenarios = [
|
||||
Scenario("compr-multifd-channels-4",
|
||||
multifd=True, multifd_channels=2),
|
||||
multifd=True, multifd_channels=4),
|
||||
Scenario("compr-multifd-channels-8",
|
||||
multifd=True, multifd_channels=8),
|
||||
Scenario("compr-multifd-channels-32",
|
||||
@ -158,4 +158,17 @@ COMPARISONS = [
|
||||
Scenario("compr-dirty-limit-50MB",
|
||||
dirty_limit=True, vcpu_dirty_limit=50),
|
||||
]),
|
||||
|
||||
# Looking at effect of multifd with
|
||||
# different compression algorithms
|
||||
Comparison("compr-multifd-compression", scenarios = [
|
||||
Scenario("compr-multifd-compression-zlib",
|
||||
multifd=True, multifd_channels=2, multifd_compression="zlib"),
|
||||
Scenario("compr-multifd-compression-zstd",
|
||||
multifd=True, multifd_channels=2, multifd_compression="zstd"),
|
||||
Scenario("compr-multifd-compression-qpl",
|
||||
multifd=True, multifd_channels=2, multifd_compression="qpl"),
|
||||
Scenario("compr-multifd-compression-uadk",
|
||||
multifd=True, multifd_channels=2, multifd_compression="uadk"),
|
||||
]),
|
||||
]
|
||||
|
@ -24,13 +24,15 @@ import sys
|
||||
import time
|
||||
|
||||
from guestperf.progress import Progress, ProgressStats
|
||||
from guestperf.report import Report
|
||||
from guestperf.report import Report, ReportResult
|
||||
from guestperf.timings import TimingRecord, Timings
|
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),
|
||||
'..', '..', '..', 'python'))
|
||||
from qemu.machine import QEMUMachine
|
||||
|
||||
# multifd supported compression algorithms
|
||||
MULTIFD_CMP_ALGS = ("zlib", "zstd", "qpl", "uadk")
|
||||
|
||||
class Engine(object):
|
||||
|
||||
@ -106,7 +108,8 @@ class Engine(object):
|
||||
info.get("dirty-limit-ring-full-time", 0),
|
||||
)
|
||||
|
||||
def _migrate(self, hardware, scenario, src, dst, connect_uri):
|
||||
def _migrate(self, hardware, scenario, src,
|
||||
dst, connect_uri, defer_migrate):
|
||||
src_qemu_time = []
|
||||
src_vcpu_time = []
|
||||
src_pid = src.get_pid()
|
||||
@ -190,6 +193,12 @@ class Engine(object):
|
||||
scenario._compression_xbzrle_cache))
|
||||
|
||||
if scenario._multifd:
|
||||
if (scenario._multifd_compression and
|
||||
(scenario._multifd_compression not in MULTIFD_CMP_ALGS)):
|
||||
raise Exception("unsupported multifd compression "
|
||||
"algorithm: %s" %
|
||||
scenario._multifd_compression)
|
||||
|
||||
resp = src.cmd("migrate-set-capabilities",
|
||||
capabilities = [
|
||||
{ "capability": "multifd",
|
||||
@ -205,6 +214,12 @@ class Engine(object):
|
||||
resp = dst.cmd("migrate-set-parameters",
|
||||
multifd_channels=scenario._multifd_channels)
|
||||
|
||||
if scenario._multifd_compression:
|
||||
resp = src.cmd("migrate-set-parameters",
|
||||
multifd_compression=scenario._multifd_compression)
|
||||
resp = dst.cmd("migrate-set-parameters",
|
||||
multifd_compression=scenario._multifd_compression)
|
||||
|
||||
if scenario._dirty_limit:
|
||||
if not hardware._dirty_ring_size:
|
||||
raise Exception("dirty ring size must be configured when "
|
||||
@ -220,6 +235,8 @@ class Engine(object):
|
||||
resp = src.cmd("migrate-set-parameters",
|
||||
vcpu_dirty_limit=scenario._vcpu_dirty_limit)
|
||||
|
||||
if defer_migrate:
|
||||
resp = dst.cmd("migrate-incoming", uri=connect_uri)
|
||||
resp = src.cmd("migrate", uri=connect_uri)
|
||||
|
||||
post_copy = False
|
||||
@ -259,7 +276,11 @@ class Engine(object):
|
||||
src_vcpu_time.extend(self._vcpu_timing(src_pid, src_threads))
|
||||
sleep_secs -= 1
|
||||
|
||||
return [progress_history, src_qemu_time, src_vcpu_time]
|
||||
result = ReportResult()
|
||||
if progress._status == "completed" and not paused:
|
||||
result = ReportResult(True)
|
||||
|
||||
return [progress_history, src_qemu_time, src_vcpu_time, result]
|
||||
|
||||
if self._verbose and (loop % 20) == 0:
|
||||
print("Iter %d: remain %5dMB of %5dMB (total %5dMB @ %5dMb/sec)" % (
|
||||
@ -373,11 +394,14 @@ class Engine(object):
|
||||
def _get_src_args(self, hardware):
|
||||
return self._get_common_args(hardware)
|
||||
|
||||
def _get_dst_args(self, hardware, uri):
|
||||
def _get_dst_args(self, hardware, uri, defer_migrate):
|
||||
tunnelled = False
|
||||
if self._dst_host != "localhost":
|
||||
tunnelled = True
|
||||
argv = self._get_common_args(hardware, tunnelled)
|
||||
|
||||
if defer_migrate:
|
||||
return argv + ["-incoming", "defer"]
|
||||
return argv + ["-incoming", uri]
|
||||
|
||||
@staticmethod
|
||||
@ -424,6 +448,7 @@ class Engine(object):
|
||||
|
||||
def run(self, hardware, scenario, result_dir=os.getcwd()):
|
||||
abs_result_dir = os.path.join(result_dir, scenario._name)
|
||||
defer_migrate = False
|
||||
|
||||
if self._transport == "tcp":
|
||||
uri = "tcp:%s:9000" % self._dst_host
|
||||
@ -439,6 +464,9 @@ class Engine(object):
|
||||
except:
|
||||
pass
|
||||
|
||||
if scenario._multifd:
|
||||
defer_migrate = True
|
||||
|
||||
if self._dst_host != "localhost":
|
||||
dstmonaddr = ("localhost", 9001)
|
||||
else:
|
||||
@ -452,7 +480,7 @@ class Engine(object):
|
||||
monitor_address=srcmonaddr)
|
||||
|
||||
dst = QEMUMachine(self._binary,
|
||||
args=self._get_dst_args(hardware, uri),
|
||||
args=self._get_dst_args(hardware, uri, defer_migrate),
|
||||
wrapper=self._get_dst_wrapper(hardware),
|
||||
name="qemu-dst-%d" % os.getpid(),
|
||||
monitor_address=dstmonaddr)
|
||||
@ -461,10 +489,12 @@ class Engine(object):
|
||||
src.launch()
|
||||
dst.launch()
|
||||
|
||||
ret = self._migrate(hardware, scenario, src, dst, uri)
|
||||
ret = self._migrate(hardware, scenario, src,
|
||||
dst, uri, defer_migrate)
|
||||
progress_history = ret[0]
|
||||
qemu_timings = ret[1]
|
||||
vcpu_timings = ret[2]
|
||||
result = ret[3]
|
||||
if uri[0:5] == "unix:" and os.path.exists(uri[5:]):
|
||||
os.remove(uri[5:])
|
||||
|
||||
@ -484,6 +514,7 @@ class Engine(object):
|
||||
Timings(self._get_timings(src) + self._get_timings(dst)),
|
||||
Timings(qemu_timings),
|
||||
Timings(vcpu_timings),
|
||||
result,
|
||||
self._binary, self._dst_host, self._kernel,
|
||||
self._initrd, self._transport, self._sleep)
|
||||
except Exception as e:
|
||||
|
@ -24,6 +24,22 @@ from guestperf.scenario import Scenario
|
||||
from guestperf.progress import Progress
|
||||
from guestperf.timings import Timings
|
||||
|
||||
class ReportResult(object):
|
||||
|
||||
def __init__(self, success=False):
|
||||
self._success = success
|
||||
|
||||
def serialize(self):
|
||||
return {
|
||||
"success": self._success,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, data):
|
||||
return cls(
|
||||
data["success"])
|
||||
|
||||
|
||||
class Report(object):
|
||||
|
||||
def __init__(self,
|
||||
@ -33,6 +49,7 @@ class Report(object):
|
||||
guest_timings,
|
||||
qemu_timings,
|
||||
vcpu_timings,
|
||||
result,
|
||||
binary,
|
||||
dst_host,
|
||||
kernel,
|
||||
@ -46,6 +63,7 @@ class Report(object):
|
||||
self._guest_timings = guest_timings
|
||||
self._qemu_timings = qemu_timings
|
||||
self._vcpu_timings = vcpu_timings
|
||||
self._result = result
|
||||
self._binary = binary
|
||||
self._dst_host = dst_host
|
||||
self._kernel = kernel
|
||||
@ -61,6 +79,7 @@ class Report(object):
|
||||
"guest_timings": self._guest_timings.serialize(),
|
||||
"qemu_timings": self._qemu_timings.serialize(),
|
||||
"vcpu_timings": self._vcpu_timings.serialize(),
|
||||
"result": self._result.serialize(),
|
||||
"binary": self._binary,
|
||||
"dst_host": self._dst_host,
|
||||
"kernel": self._kernel,
|
||||
@ -78,6 +97,7 @@ class Report(object):
|
||||
Timings.deserialize(data["guest_timings"]),
|
||||
Timings.deserialize(data["qemu_timings"]),
|
||||
Timings.deserialize(data["vcpu_timings"]),
|
||||
ReportResult.deserialize(data["result"]),
|
||||
data["binary"],
|
||||
data["dst_host"],
|
||||
data["kernel"],
|
||||
|
@ -30,7 +30,7 @@ class Scenario(object):
|
||||
auto_converge=False, auto_converge_step=10,
|
||||
compression_mt=False, compression_mt_threads=1,
|
||||
compression_xbzrle=False, compression_xbzrle_cache=10,
|
||||
multifd=False, multifd_channels=2,
|
||||
multifd=False, multifd_channels=2, multifd_compression="",
|
||||
dirty_limit=False, x_vcpu_dirty_limit_period=500,
|
||||
vcpu_dirty_limit=1):
|
||||
|
||||
@ -61,6 +61,7 @@ class Scenario(object):
|
||||
|
||||
self._multifd = multifd
|
||||
self._multifd_channels = multifd_channels
|
||||
self._multifd_compression = multifd_compression
|
||||
|
||||
self._dirty_limit = dirty_limit
|
||||
self._x_vcpu_dirty_limit_period = x_vcpu_dirty_limit_period
|
||||
@ -85,6 +86,7 @@ class Scenario(object):
|
||||
"compression_xbzrle_cache": self._compression_xbzrle_cache,
|
||||
"multifd": self._multifd,
|
||||
"multifd_channels": self._multifd_channels,
|
||||
"multifd_compression": self._multifd_compression,
|
||||
"dirty_limit": self._dirty_limit,
|
||||
"x_vcpu_dirty_limit_period": self._x_vcpu_dirty_limit_period,
|
||||
"vcpu_dirty_limit": self._vcpu_dirty_limit,
|
||||
@ -109,4 +111,5 @@ class Scenario(object):
|
||||
data["compression_xbzrle"],
|
||||
data["compression_xbzrle_cache"],
|
||||
data["multifd"],
|
||||
data["multifd_channels"])
|
||||
data["multifd_channels"],
|
||||
data["multifd_compression"])
|
||||
|
@ -131,6 +131,8 @@ class Shell(BaseShell):
|
||||
action="store_true")
|
||||
parser.add_argument("--multifd-channels", dest="multifd_channels",
|
||||
default=2, type=int)
|
||||
parser.add_argument("--multifd-compression", dest="multifd_compression",
|
||||
default="")
|
||||
|
||||
parser.add_argument("--dirty-limit", dest="dirty_limit", default=False,
|
||||
action="store_true")
|
||||
@ -167,6 +169,7 @@ class Shell(BaseShell):
|
||||
|
||||
multifd=args.multifd,
|
||||
multifd_channels=args.multifd_channels,
|
||||
multifd_compression=args.multifd_compression,
|
||||
|
||||
dirty_limit=args.dirty_limit,
|
||||
x_vcpu_dirty_limit_period=\
|
||||
|
@ -236,6 +236,7 @@ char *resolve_machine_version(const char *alias, const char *var1,
|
||||
typedef struct {
|
||||
char *name;
|
||||
void (*func)(void);
|
||||
void (*func_full)(void *);
|
||||
} MigrationTest;
|
||||
|
||||
static void migration_test_destroy(gpointer data)
|
||||
@ -265,6 +266,29 @@ void migration_test_add(const char *path, void (*fn)(void))
|
||||
migration_test_destroy);
|
||||
}
|
||||
|
||||
static void migration_test_wrapper_full(const void *data)
|
||||
{
|
||||
MigrationTest *test = (MigrationTest *)data;
|
||||
|
||||
g_test_message("Running /%s%s", qtest_get_arch(), test->name);
|
||||
test->func_full(test->name);
|
||||
}
|
||||
|
||||
void migration_test_add_suffix(const char *path, const char *suffix,
|
||||
void (*fn)(void *))
|
||||
{
|
||||
MigrationTest *test = g_new0(MigrationTest, 1);
|
||||
|
||||
g_assert(g_str_has_suffix(path, "/"));
|
||||
g_assert(!g_str_has_prefix(suffix, "/"));
|
||||
|
||||
test->func_full = fn;
|
||||
test->name = g_strconcat(path, suffix, NULL);
|
||||
|
||||
qtest_add_data_func_full(test->name, test, migration_test_wrapper_full,
|
||||
migration_test_destroy);
|
||||
}
|
||||
|
||||
#ifdef O_DIRECT
|
||||
/*
|
||||
* Probe for O_DIRECT support on the filesystem. Since this is used
|
||||
|
@ -51,6 +51,8 @@ static inline bool probe_o_direct_support(const char *tmpfs)
|
||||
bool ufd_version_check(bool *uffd_feature_thread_id);
|
||||
bool kvm_dirty_ring_supported(void);
|
||||
void migration_test_add(const char *path, void (*fn)(void));
|
||||
void migration_test_add_suffix(const char *path, const char *suffix,
|
||||
void (*fn)(void *));
|
||||
char *migrate_get_connect_uri(QTestState *who);
|
||||
void migrate_set_ports(QTestState *to, QList *channel_list);
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "migration/migration-util.h"
|
||||
#include "ppc-util.h"
|
||||
#include "qobject/qlist.h"
|
||||
#include "qapi-types-migration.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/range.h"
|
||||
@ -536,6 +537,161 @@ static void test_multifd_tcp_cancel(void)
|
||||
migrate_end(from, to2, true);
|
||||
}
|
||||
|
||||
static void test_cancel_src_after_failed(QTestState *from, QTestState *to,
|
||||
const char *uri, const char *phase)
|
||||
{
|
||||
/*
|
||||
* No migrate_incoming_qmp() at the start to force source into
|
||||
* failed state during migrate_qmp().
|
||||
*/
|
||||
|
||||
wait_for_serial("src_serial");
|
||||
migrate_ensure_converge(from);
|
||||
|
||||
migrate_qmp(from, to, uri, NULL, "{}");
|
||||
|
||||
migration_event_wait(from, phase);
|
||||
migrate_cancel(from);
|
||||
|
||||
/* cancelling will not move the migration out of 'failed' */
|
||||
|
||||
wait_for_migration_status(from, "failed",
|
||||
(const char * []) { "completed", NULL });
|
||||
|
||||
/*
|
||||
* Not waiting for the destination because it never started
|
||||
* migration.
|
||||
*/
|
||||
}
|
||||
|
||||
static void test_cancel_src_after_cancelled(QTestState *from, QTestState *to,
|
||||
const char *uri, const char *phase)
|
||||
{
|
||||
migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
|
||||
|
||||
wait_for_serial("src_serial");
|
||||
migrate_ensure_converge(from);
|
||||
|
||||
migrate_qmp(from, to, uri, NULL, "{}");
|
||||
|
||||
/* To move to cancelled/cancelling */
|
||||
migrate_cancel(from);
|
||||
migration_event_wait(from, phase);
|
||||
|
||||
/* The migrate_cancel under test */
|
||||
migrate_cancel(from);
|
||||
|
||||
wait_for_migration_status(from, "cancelled",
|
||||
(const char * []) { "completed", NULL });
|
||||
|
||||
wait_for_migration_status(to, "failed",
|
||||
(const char * []) { "completed", NULL });
|
||||
}
|
||||
|
||||
static void test_cancel_src_after_complete(QTestState *from, QTestState *to,
|
||||
const char *uri, const char *phase)
|
||||
{
|
||||
migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
|
||||
|
||||
wait_for_serial("src_serial");
|
||||
migrate_ensure_converge(from);
|
||||
|
||||
migrate_qmp(from, to, uri, NULL, "{}");
|
||||
|
||||
migration_event_wait(from, phase);
|
||||
migrate_cancel(from);
|
||||
|
||||
/*
|
||||
* qmp_migrate_cancel() exits early if migration is not running
|
||||
* anymore, the status will not change to cancelled.
|
||||
*/
|
||||
wait_for_migration_complete(from);
|
||||
wait_for_migration_complete(to);
|
||||
}
|
||||
|
||||
static void test_cancel_src_after_none(QTestState *from, QTestState *to,
|
||||
const char *uri, const char *phase)
|
||||
{
|
||||
/*
|
||||
* Test that cancelling without a migration happening does not
|
||||
* affect subsequent migrations
|
||||
*/
|
||||
migrate_cancel(to);
|
||||
|
||||
wait_for_serial("src_serial");
|
||||
migrate_cancel(from);
|
||||
|
||||
migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
|
||||
|
||||
migrate_ensure_converge(from);
|
||||
migrate_qmp(from, to, uri, NULL, "{}");
|
||||
|
||||
wait_for_migration_complete(from);
|
||||
wait_for_migration_complete(to);
|
||||
}
|
||||
|
||||
static void test_cancel_src_pre_switchover(QTestState *from, QTestState *to,
|
||||
const char *uri, const char *phase)
|
||||
{
|
||||
migrate_set_capability(from, "pause-before-switchover", true);
|
||||
migrate_set_capability(to, "pause-before-switchover", true);
|
||||
|
||||
migrate_set_capability(from, "multifd", true);
|
||||
migrate_set_capability(to, "multifd", true);
|
||||
|
||||
migrate_incoming_qmp(to, uri, NULL, "{ 'exit-on-error': false }");
|
||||
|
||||
wait_for_serial("src_serial");
|
||||
migrate_ensure_converge(from);
|
||||
|
||||
migrate_qmp(from, to, uri, NULL, "{}");
|
||||
|
||||
migration_event_wait(from, phase);
|
||||
migrate_cancel(from);
|
||||
migration_event_wait(from, "cancelling");
|
||||
|
||||
wait_for_migration_status(from, "cancelled",
|
||||
(const char * []) { "completed", NULL });
|
||||
|
||||
wait_for_migration_status(to, "failed",
|
||||
(const char * []) { "completed", NULL });
|
||||
}
|
||||
|
||||
static void test_cancel_src_after_status(void *opaque)
|
||||
{
|
||||
const char *test_path = opaque;
|
||||
g_autofree char *phase = g_path_get_basename(test_path);
|
||||
g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
|
||||
QTestState *from, *to;
|
||||
MigrateStart args = {
|
||||
.hide_stderr = true,
|
||||
};
|
||||
|
||||
if (migrate_start(&from, &to, "defer", &args)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_str_equal(phase, "cancelling") ||
|
||||
g_str_equal(phase, "cancelled")) {
|
||||
test_cancel_src_after_cancelled(from, to, uri, phase);
|
||||
|
||||
} else if (g_str_equal(phase, "completed")) {
|
||||
test_cancel_src_after_complete(from, to, uri, phase);
|
||||
|
||||
} else if (g_str_equal(phase, "failed")) {
|
||||
test_cancel_src_after_failed(from, to, uri, phase);
|
||||
|
||||
} else if (g_str_equal(phase, "none")) {
|
||||
test_cancel_src_after_none(from, to, uri, phase);
|
||||
|
||||
} else {
|
||||
/* any state that comes before pre-switchover */
|
||||
test_cancel_src_pre_switchover(from, to, uri, phase);
|
||||
}
|
||||
|
||||
migrate_end(from, to, false);
|
||||
}
|
||||
|
||||
static void calc_dirty_rate(QTestState *who, uint64_t calc_time)
|
||||
{
|
||||
qtest_qmp_assert_success(who,
|
||||
@ -1018,4 +1174,24 @@ void migration_test_add_precopy(MigrationTestEnv *env)
|
||||
test_vcpu_dirty_limit);
|
||||
}
|
||||
}
|
||||
|
||||
/* ensure new status don't go unnoticed */
|
||||
assert(MIGRATION_STATUS__MAX == 15);
|
||||
|
||||
for (int i = MIGRATION_STATUS_NONE; i < MIGRATION_STATUS__MAX; i++) {
|
||||
switch (i) {
|
||||
case MIGRATION_STATUS_DEVICE: /* happens too fast */
|
||||
case MIGRATION_STATUS_WAIT_UNPLUG: /* no support in tests */
|
||||
case MIGRATION_STATUS_COLO: /* no support in tests */
|
||||
case MIGRATION_STATUS_POSTCOPY_ACTIVE: /* postcopy can't be cancelled */
|
||||
case MIGRATION_STATUS_POSTCOPY_PAUSED:
|
||||
case MIGRATION_STATUS_POSTCOPY_RECOVER_SETUP:
|
||||
case MIGRATION_STATUS_POSTCOPY_RECOVER:
|
||||
continue;
|
||||
default:
|
||||
migration_test_add_suffix("/migration/cancel/src/after/",
|
||||
MigrationStatus_str(i),
|
||||
test_cancel_src_after_status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,8 +158,7 @@ static void test_crypto_tls_session_psk(void)
|
||||
rv = qcrypto_tls_session_handshake(serverSess,
|
||||
&error_abort);
|
||||
g_assert(rv >= 0);
|
||||
if (qcrypto_tls_session_get_handshake_status(serverSess) ==
|
||||
QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
|
||||
if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
|
||||
serverShake = true;
|
||||
}
|
||||
}
|
||||
@ -167,8 +166,7 @@ static void test_crypto_tls_session_psk(void)
|
||||
rv = qcrypto_tls_session_handshake(clientSess,
|
||||
&error_abort);
|
||||
g_assert(rv >= 0);
|
||||
if (qcrypto_tls_session_get_handshake_status(clientSess) ==
|
||||
QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
|
||||
if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
|
||||
clientShake = true;
|
||||
}
|
||||
}
|
||||
@ -352,8 +350,7 @@ static void test_crypto_tls_session_x509(const void *opaque)
|
||||
rv = qcrypto_tls_session_handshake(serverSess,
|
||||
&error_abort);
|
||||
g_assert(rv >= 0);
|
||||
if (qcrypto_tls_session_get_handshake_status(serverSess) ==
|
||||
QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
|
||||
if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
|
||||
serverShake = true;
|
||||
}
|
||||
}
|
||||
@ -361,8 +358,7 @@ static void test_crypto_tls_session_x509(const void *opaque)
|
||||
rv = qcrypto_tls_session_handshake(clientSess,
|
||||
&error_abort);
|
||||
g_assert(rv >= 0);
|
||||
if (qcrypto_tls_session_get_handshake_status(clientSess) ==
|
||||
QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
|
||||
if (rv == QCRYPTO_TLS_HANDSHAKE_COMPLETE) {
|
||||
clientShake = true;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user