Skip to content

Commit

Permalink
Merge tag 'pull-migration-20220516a' of https://gitlab.com/dagrh/qemu
Browse files Browse the repository at this point in the history
…into staging

Migration pull 2022-05-16

(This replaces the 28th April through 10th May sets)
Compared to that last set it just has the Alpine
uring check that Leo has added; although that's also
now fixed upstream in Alpine.

It contains:
  TLS test fixes from Dan
  Zerocopy migration feature from Leo

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEERfXHG0oMt/uXep+pBRYzHrxb/ecFAmKCY80ACgkQBRYzHrxb
# /eeEEhAAoUogch7ifxFItr1EA0AU6Sgd3Dcn8wY9pm0NySVg7OcIpk1H++A3CgIh
# bubJSwRmpIxGw+5q5w5OvBukFCGYMlAK7J8k1tZmaqdKS8wD0ZwhpPyqTWd14Q/v
# xXSGOQfHMMvbBILiXPjSkfNw8yKJhZr+lW39uMz/kZRwZUmTcrdKAT3Q8PW+1DI9
# v3mNoFNXqtDlHcQ4nQ1TGk/RDO6oXDlTJwdnjoJT3Dopf8Jhl2etvZgVk2kOf4i5
# LmJbSVBr5FNOhJ6P4WL4OEQFOiXXquKdfuGTXIGGhkrW2WkPZulQwB6uO4Gv1wf2
# aj9bLDAFoPxFx2zYS6S/9L6rGeBMcTL9xHCfzyylM6YRjoscRdxXc67PClw71JUy
# regsoSQej0FpmsGx0uuAsDjCELleVIjeYzuQo5OYOP1BCg/5unLIrMgkyQw7COJI
# w+MIZq7IqvUTehU2yXpUGOqPkyDLBlib92dMRgqqG9r9UU7iL3BREbGW4ugW+GM2
# a9k8W9HjyDIIODsdXy1ugPHgjr/arHDAPgYosJMLvjTfdJDcIldAw6CbCcqhCDES
# UOjMVN9VS+716nY2AqvtEHxf47YwqmeRb+tg4SQ0dHLH5Pvfe2bk1sbZiiQpcelt
# Bd88yeBOpcmdzJVur2V4fEZXu5JB/qt/jeJeQa82hS3k93PWm/w=
# =Axhk
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 16 May 2022 07:46:37 AM PDT
# gpg:                using RSA key 45F5C71B4A0CB7FB977A9FA90516331EBC5BFDE7
# gpg: Good signature from "Dr. David Alan Gilbert (RH2) <dgilbert@redhat.com>" [full]

* tag 'pull-migration-20220516a' of https://gitlab.com/dagrh/qemu:
  multifd: Implement zero copy write in multifd migration (multifd-zero-copy)
  multifd: Send header packet without flags if zero-copy-send is enabled
  multifd: multifd_send_sync_main now returns negative on error
  migration: Add migrate_use_tls() helper
  migration: Add zero-copy-send parameter for QMP/HMP for Linux
  QIOChannelSocket: Implement io_writev zero copy flag & io_flush for CONFIG_LINUX
  QIOChannel: Add flags on io_writev and introduce io_flush callback
  meson.build: Fix docker-test-build@alpine when including linux/errqueue.h
  tests: ensure migration status isn't reported as failed
  tests: add multifd migration tests of TLS with x509 credentials
  tests: add multifd migration tests of TLS with PSK credentials
  tests: convert multifd migration tests to use common helper
  tests: convert XBZRLE migration test to use common helper
  tests: add migration tests of TLS with x509 credentials
  tests: add migration tests of TLS with PSK credentials
  tests: add more helper macros for creating TLS x509 certs
  tests: fix encoding of IP addresses in x509 certs

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
  • Loading branch information
rth7680 committed May 16, 2022
2 parents b935385 + 5b1d9ba commit 54b592c
Show file tree
Hide file tree
Showing 33 changed files with 1,295 additions and 139 deletions.
2 changes: 1 addition & 1 deletion chardev/char-io.c
Expand Up @@ -122,7 +122,7 @@ int io_channel_send_full(QIOChannel *ioc,

ret = qio_channel_writev_full(
ioc, &iov, 1,
fds, nfds, NULL);
fds, nfds, 0, NULL);
if (ret == QIO_CHANNEL_ERR_BLOCK) {
if (offset) {
return offset;
Expand Down
2 changes: 1 addition & 1 deletion hw/remote/mpqemu-link.c
Expand Up @@ -68,7 +68,7 @@ bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, Error **errp)
}

if (!qio_channel_writev_full_all(ioc, send, G_N_ELEMENTS(send),
fds, nfds, errp)) {
fds, nfds, 0, errp)) {
ret = true;
} else {
trace_mpqemu_send_io_error(msg->cmd, msg->size, nfds);
Expand Down
2 changes: 2 additions & 0 deletions include/io/channel-socket.h
Expand Up @@ -47,6 +47,8 @@ struct QIOChannelSocket {
socklen_t localAddrLen;
struct sockaddr_storage remoteAddr;
socklen_t remoteAddrLen;
ssize_t zero_copy_queued;
ssize_t zero_copy_sent;
};


Expand Down
38 changes: 37 additions & 1 deletion include/io/channel.h
Expand Up @@ -32,12 +32,15 @@ OBJECT_DECLARE_TYPE(QIOChannel, QIOChannelClass,

#define QIO_CHANNEL_ERR_BLOCK -2

#define QIO_CHANNEL_WRITE_FLAG_ZERO_COPY 0x1

typedef enum QIOChannelFeature QIOChannelFeature;

enum QIOChannelFeature {
QIO_CHANNEL_FEATURE_FD_PASS,
QIO_CHANNEL_FEATURE_SHUTDOWN,
QIO_CHANNEL_FEATURE_LISTEN,
QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY,
};


Expand Down Expand Up @@ -104,6 +107,7 @@ struct QIOChannelClass {
size_t niov,
int *fds,
size_t nfds,
int flags,
Error **errp);
ssize_t (*io_readv)(QIOChannel *ioc,
const struct iovec *iov,
Expand Down Expand Up @@ -136,6 +140,8 @@ struct QIOChannelClass {
IOHandler *io_read,
IOHandler *io_write,
void *opaque);
int (*io_flush)(QIOChannel *ioc,
Error **errp);
};

/* General I/O handling functions */
Expand Down Expand Up @@ -228,6 +234,7 @@ ssize_t qio_channel_readv_full(QIOChannel *ioc,
* @niov: the length of the @iov array
* @fds: an array of file handles to send
* @nfds: number of file handles in @fds
* @flags: write flags (QIO_CHANNEL_WRITE_FLAG_*)
* @errp: pointer to a NULL-initialized error object
*
* Write data to the IO channel, reading it from the
Expand Down Expand Up @@ -260,6 +267,7 @@ ssize_t qio_channel_writev_full(QIOChannel *ioc,
size_t niov,
int *fds,
size_t nfds,
int flags,
Error **errp);

/**
Expand Down Expand Up @@ -837,6 +845,7 @@ int qio_channel_readv_full_all(QIOChannel *ioc,
* @niov: the length of the @iov array
* @fds: an array of file handles to send
* @nfds: number of file handles in @fds
* @flags: write flags (QIO_CHANNEL_WRITE_FLAG_*)
* @errp: pointer to a NULL-initialized error object
*
*
Expand All @@ -846,13 +855,40 @@ int qio_channel_readv_full_all(QIOChannel *ioc,
* to be written, yielding from the current coroutine
* if required.
*
* If QIO_CHANNEL_WRITE_FLAG_ZERO_COPY is passed in flags,
* instead of waiting for all requested data to be written,
* this function will wait until it's all queued for writing.
* In this case, if the buffer gets changed between queueing and
* sending, the updated buffer will be sent. If this is not a
* desired behavior, it's suggested to call qio_channel_flush()
* before reusing the buffer.
*
* Returns: 0 if all bytes were written, or -1 on error
*/

int qio_channel_writev_full_all(QIOChannel *ioc,
const struct iovec *iov,
size_t niov,
int *fds, size_t nfds,
Error **errp);
int flags, Error **errp);

/**
* qio_channel_flush:
* @ioc: the channel object
* @errp: pointer to a NULL-initialized error object
*
* Will block until every packet queued with
* qio_channel_writev_full() + QIO_CHANNEL_WRITE_FLAG_ZERO_COPY
* is sent, or return in case of any error.
*
* If not implemented, acts as a no-op, and returns 0.
*
* Returns -1 if any error is found,
* 1 if every send failed to use zero copy.
* 0 otherwise.
*/

int qio_channel_flush(QIOChannel *ioc,
Error **errp);

#endif /* QIO_CHANNEL_H */
1 change: 1 addition & 0 deletions io/channel-buffer.c
Expand Up @@ -81,6 +81,7 @@ static ssize_t qio_channel_buffer_writev(QIOChannel *ioc,
size_t niov,
int *fds,
size_t nfds,
int flags,
Error **errp)
{
QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
Expand Down
1 change: 1 addition & 0 deletions io/channel-command.c
Expand Up @@ -276,6 +276,7 @@ static ssize_t qio_channel_command_writev(QIOChannel *ioc,
size_t niov,
int *fds,
size_t nfds,
int flags,
Error **errp)
{
QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
Expand Down
1 change: 1 addition & 0 deletions io/channel-file.c
Expand Up @@ -114,6 +114,7 @@ static ssize_t qio_channel_file_writev(QIOChannel *ioc,
size_t niov,
int *fds,
size_t nfds,
int flags,
Error **errp)
{
QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
Expand Down
118 changes: 114 additions & 4 deletions io/channel-socket.c
Expand Up @@ -25,6 +25,14 @@
#include "io/channel-watch.h"
#include "trace.h"
#include "qapi/clone-visitor.h"
#ifdef CONFIG_LINUX
#include <linux/errqueue.h>
#include <sys/socket.h>

#if (defined(MSG_ZEROCOPY) && defined(SO_ZEROCOPY))
#define QEMU_MSG_ZEROCOPY
#endif
#endif

#define SOCKET_MAX_FDS 16

Expand Down Expand Up @@ -54,6 +62,8 @@ qio_channel_socket_new(void)

sioc = QIO_CHANNEL_SOCKET(object_new(TYPE_QIO_CHANNEL_SOCKET));
sioc->fd = -1;
sioc->zero_copy_queued = 0;
sioc->zero_copy_sent = 0;

ioc = QIO_CHANNEL(sioc);
qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
Expand Down Expand Up @@ -153,6 +163,16 @@ int qio_channel_socket_connect_sync(QIOChannelSocket *ioc,
return -1;
}

#ifdef QEMU_MSG_ZEROCOPY
int ret, v = 1;
ret = setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &v, sizeof(v));
if (ret == 0) {
/* Zero copy available on host */
qio_channel_set_feature(QIO_CHANNEL(ioc),
QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY);
}
#endif

return 0;
}

Expand Down Expand Up @@ -524,6 +544,7 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
size_t niov,
int *fds,
size_t nfds,
int flags,
Error **errp)
{
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
Expand All @@ -532,6 +553,7 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)];
size_t fdsize = sizeof(int) * nfds;
struct cmsghdr *cmsg;
int sflags = 0;

memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS));

Expand All @@ -556,15 +578,31 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
memcpy(CMSG_DATA(cmsg), fds, fdsize);
}

#ifdef QEMU_MSG_ZEROCOPY
if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) {
sflags = MSG_ZEROCOPY;
}
#endif

retry:
ret = sendmsg(sioc->fd, &msg, 0);
ret = sendmsg(sioc->fd, &msg, sflags);
if (ret <= 0) {
if (errno == EAGAIN) {
switch (errno) {
case EAGAIN:
return QIO_CHANNEL_ERR_BLOCK;
}
if (errno == EINTR) {
case EINTR:
goto retry;
#ifdef QEMU_MSG_ZEROCOPY
case ENOBUFS:
if (sflags & MSG_ZEROCOPY) {
error_setg_errno(errp, errno,
"Process can't lock enough memory for using MSG_ZEROCOPY");
return -1;
}
break;
#endif
}

error_setg_errno(errp, errno,
"Unable to write to socket");
return -1;
Expand Down Expand Up @@ -619,6 +657,7 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
size_t niov,
int *fds,
size_t nfds,
int flags,
Error **errp)
{
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
Expand Down Expand Up @@ -657,6 +696,74 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
}
#endif /* WIN32 */


#ifdef QEMU_MSG_ZEROCOPY
static int qio_channel_socket_flush(QIOChannel *ioc,
Error **errp)
{
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
struct msghdr msg = {};
struct sock_extended_err *serr;
struct cmsghdr *cm;
char control[CMSG_SPACE(sizeof(*serr))];
int received;
int ret = 1;

msg.msg_control = control;
msg.msg_controllen = sizeof(control);
memset(control, 0, sizeof(control));

while (sioc->zero_copy_sent < sioc->zero_copy_queued) {
received = recvmsg(sioc->fd, &msg, MSG_ERRQUEUE);
if (received < 0) {
switch (errno) {
case EAGAIN:
/* Nothing on errqueue, wait until something is available */
qio_channel_wait(ioc, G_IO_ERR);
continue;
case EINTR:
continue;
default:
error_setg_errno(errp, errno,
"Unable to read errqueue");
return -1;
}
}

cm = CMSG_FIRSTHDR(&msg);
if (cm->cmsg_level != SOL_IP &&
cm->cmsg_type != IP_RECVERR) {
error_setg_errno(errp, EPROTOTYPE,
"Wrong cmsg in errqueue");
return -1;
}

serr = (void *) CMSG_DATA(cm);
if (serr->ee_errno != SO_EE_ORIGIN_NONE) {
error_setg_errno(errp, serr->ee_errno,
"Error on socket");
return -1;
}
if (serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) {
error_setg_errno(errp, serr->ee_origin,
"Error not from zero copy");
return -1;
}

/* No errors, count successfully finished sendmsg()*/
sioc->zero_copy_sent += serr->ee_data - serr->ee_info + 1;

/* If any sendmsg() succeeded using zero copy, return 0 at the end */
if (serr->ee_code != SO_EE_CODE_ZEROCOPY_COPIED) {
ret = 0;
}
}

return ret;
}

#endif /* QEMU_MSG_ZEROCOPY */

static int
qio_channel_socket_set_blocking(QIOChannel *ioc,
bool enabled,
Expand Down Expand Up @@ -787,6 +894,9 @@ static void qio_channel_socket_class_init(ObjectClass *klass,
ioc_klass->io_set_delay = qio_channel_socket_set_delay;
ioc_klass->io_create_watch = qio_channel_socket_create_watch;
ioc_klass->io_set_aio_fd_handler = qio_channel_socket_set_aio_fd_handler;
#ifdef QEMU_MSG_ZEROCOPY
ioc_klass->io_flush = qio_channel_socket_flush;
#endif
}

static const TypeInfo qio_channel_socket_info = {
Expand Down
1 change: 1 addition & 0 deletions io/channel-tls.c
Expand Up @@ -301,6 +301,7 @@ static ssize_t qio_channel_tls_writev(QIOChannel *ioc,
size_t niov,
int *fds,
size_t nfds,
int flags,
Error **errp)
{
QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
Expand Down
1 change: 1 addition & 0 deletions io/channel-websock.c
Expand Up @@ -1127,6 +1127,7 @@ static ssize_t qio_channel_websock_writev(QIOChannel *ioc,
size_t niov,
int *fds,
size_t nfds,
int flags,
Error **errp)
{
QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
Expand Down

0 comments on commit 54b592c

Please sign in to comment.