From: "manish.mishra" <manish.mishra@nutanix.com>
To: qemu-devel@nongnu.org
Cc: berrange@redhat.com, peterx@redhat.com,
prerna.saxena@nutanix.com, quintela@redhat.com,
dgilbert@redhat.com, lsoaresp@redhat.com
Subject: Re: [PATCH 1/2] io: Add support for MSG_PEEK for socket channel
Date: Sat, 19 Nov 2022 15:10:37 +0530 [thread overview]
Message-ID: <36c26e0c-cd1d-854f-f14d-e1935a84dae7@nutanix.com> (raw)
In-Reply-To: <20221119093615.158072-1-manish.mishra@nutanix.com>
On 19/11/22 3:06 pm, manish.mishra wrote:
> MSG_PEEK reads from the peek of channel, The data is treated as
> unread and the next read shall still return this data. This
> support is currently added only for socket class. Extra parameter
> 'flags' is added to io_readv calls to pass extra read flags like
> MSG_PEEK.
> ---
> chardev/char-socket.c | 4 +-
> include/io/channel.h | 83 +++++++++++++++++++++++++++++
> io/channel-buffer.c | 1 +
> io/channel-command.c | 1 +
> io/channel-file.c | 1 +
> io/channel-null.c | 1 +
> io/channel-socket.c | 16 +++++-
> io/channel-tls.c | 1 +
> io/channel-websock.c | 1 +
> io/channel.c | 73 +++++++++++++++++++++++--
> migration/channel-block.c | 1 +
> scsi/qemu-pr-helper.c | 2 +-
> tests/qtest/tpm-emu.c | 2 +-
> tests/unit/test-io-channel-socket.c | 1 +
> util/vhost-user-server.c | 2 +-
> 15 files changed, 179 insertions(+), 11 deletions(-)
>
> diff --git a/chardev/char-socket.c b/chardev/char-socket.c
> index 879564aa8a..5afce9a464 100644
> --- a/chardev/char-socket.c
> +++ b/chardev/char-socket.c
> @@ -283,11 +283,11 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
> if (qio_channel_has_feature(s->ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
> ret = qio_channel_readv_full(s->ioc, &iov, 1,
> &msgfds, &msgfds_num,
> - NULL);
> + 0, NULL);
> } else {
> ret = qio_channel_readv_full(s->ioc, &iov, 1,
> NULL, NULL,
> - NULL);
> + 0, NULL);
> }
>
> if (msgfds_num) {
> diff --git a/include/io/channel.h b/include/io/channel.h
> index c680ee7480..cbcde4b88f 100644
> --- a/include/io/channel.h
> +++ b/include/io/channel.h
> @@ -34,6 +34,8 @@ OBJECT_DECLARE_TYPE(QIOChannel, QIOChannelClass,
>
> #define QIO_CHANNEL_WRITE_FLAG_ZERO_COPY 0x1
>
> +#define QIO_CHANNEL_READ_FLAG_MSG_PEEK 0x1
> +
> typedef enum QIOChannelFeature QIOChannelFeature;
>
> enum QIOChannelFeature {
> @@ -41,6 +43,7 @@ enum QIOChannelFeature {
> QIO_CHANNEL_FEATURE_SHUTDOWN,
> QIO_CHANNEL_FEATURE_LISTEN,
> QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY,
> + QIO_CHANNEL_FEATURE_READ_MSG_PEEK,
> };
>
>
> @@ -114,6 +117,7 @@ struct QIOChannelClass {
> size_t niov,
> int **fds,
> size_t *nfds,
> + int flags,
> Error **errp);
> int (*io_close)(QIOChannel *ioc,
> Error **errp);
> @@ -188,6 +192,7 @@ void qio_channel_set_name(QIOChannel *ioc,
> * @niov: the length of the @iov array
> * @fds: pointer to an array that will received file handles
> * @nfds: pointer filled with number of elements in @fds on return
> + * @flags: read flags (QIO_CHANNEL_READ_FLAG_*)
> * @errp: pointer to a NULL-initialized error object
> *
> * Read data from the IO channel, storing it in the
> @@ -224,6 +229,7 @@ ssize_t qio_channel_readv_full(QIOChannel *ioc,
> size_t niov,
> int **fds,
> size_t *nfds,
> + int flags,
> Error **errp);
>
>
> @@ -300,6 +306,34 @@ int qio_channel_readv_all_eof(QIOChannel *ioc,
> size_t niov,
> Error **errp);
>
> +/**
> + * qio_channel_readv_peek_all_eof:
> + * @ioc: the channel object
> + * @iov: the array of memory regions to read data into
> + * @niov: the length of the @iov array
> + * @errp: pointer to a NULL-initialized error object
> + *
> + * Read data from the peek of IO channel without
> + * actually removing it from channel buffer, storing
> + * it in the memory regions referenced by @iov. Each
> + * element in the @iov will be fully populated with
> + * data before the next one is used. The @niov
> + * parameter specifies the total number of elements
> + * in @iov.
> + *
> + * The function will wait for all requested data
> + * to be read, yielding from the current coroutine
> + * if required.
> + *
> + * Returns: 1 if all bytes were read, 0 if end-of-file
> + * occurs without data, or -1 on error
> + */
> +int qio_channel_readv_peek_all_eof(QIOChannel *ioc,
> + const struct iovec *iov,
> + size_t niov,
> + Error **errp);
> +
> +
> /**
> * qio_channel_readv_all:
> * @ioc: the channel object
> @@ -328,6 +362,34 @@ int qio_channel_readv_all(QIOChannel *ioc,
> Error **errp);
>
>
> +/**
> + * qio_channel_readv_peek_all:
> + * @ioc: the channel object
> + * @iov: the array of memory regions to read data into
> + * @niov: the length of the @iov array
> + * @errp: pointer to a NULL-initialized error object
> + *
> + * Read data from the the peek of IO channel without
> + * removing from channel buffer, storing it in the
> + * memory regions referenced by @iov. Each element
> + * in the @iov will be fully populated with data
> + * before the next one is used. The @niov parameter
> + * specifies the total number of elements in @iov.
> + *
> + * The function will wait for all requested data
> + * to be read, yielding from the current coroutine
> + * if required.
> + *
> + * If end-of-file occurs before all requested data
> + * has been read, an error will be reported.
> + *
> + * Returns: 0 if all bytes were read, or -1 on error
> + */
> +int qio_channel_readv_peek_all(QIOChannel *ioc,
> + const struct iovec *iov,
> + size_t niov,
> + Error **errp);
> +
> /**
> * qio_channel_writev_all:
> * @ioc: the channel object
> @@ -456,6 +518,27 @@ int qio_channel_read_all(QIOChannel *ioc,
> size_t buflen,
> Error **errp);
>
> +/**
> + * qio_channel_read_peek_all:
> + * @ioc: the channel object
> + * @buf: the memory region to read data into
> + * @buflen: the number of bytes to @buf
> + * @errp: pointer to a NULL-initialized error object
> + *
> + * Reads @buflen bytes from the peek of channel into @buf without
> + * removing it from channel buffer, possibly blocking or (if the
> + * channel is non-blocking) yielding from the current coroutine
> + * multiple times until the entire content is read. If end-of-file
> + * occurs it will return an error rather than a short-read. Otherwise
> + * behaves as qio_channel_read().
> + *
> + * Returns: 0 if all bytes were read, or -1 on error
> + */
> +int qio_channel_read_peek_all(QIOChannel *ioc,
> + const char *buf,
> + size_t buflen,
> + Error **errp);
> +
> /**
> * qio_channel_write_all:
> * @ioc: the channel object
> diff --git a/io/channel-buffer.c b/io/channel-buffer.c
> index bf52011be2..8096180f85 100644
> --- a/io/channel-buffer.c
> +++ b/io/channel-buffer.c
> @@ -54,6 +54,7 @@ static ssize_t qio_channel_buffer_readv(QIOChannel *ioc,
> size_t niov,
> int **fds,
> size_t *nfds,
> + int flags,
> Error **errp)
> {
> QIOChannelBuffer *bioc = QIO_CHANNEL_BUFFER(ioc);
> diff --git a/io/channel-command.c b/io/channel-command.c
> index 74516252ba..e7edd091af 100644
> --- a/io/channel-command.c
> +++ b/io/channel-command.c
> @@ -203,6 +203,7 @@ static ssize_t qio_channel_command_readv(QIOChannel *ioc,
> size_t niov,
> int **fds,
> size_t *nfds,
> + int flags,
> Error **errp)
> {
> QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
> diff --git a/io/channel-file.c b/io/channel-file.c
> index b67687c2aa..d76663e6ae 100644
> --- a/io/channel-file.c
> +++ b/io/channel-file.c
> @@ -86,6 +86,7 @@ static ssize_t qio_channel_file_readv(QIOChannel *ioc,
> size_t niov,
> int **fds,
> size_t *nfds,
> + int flags,
> Error **errp)
> {
> QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
> diff --git a/io/channel-null.c b/io/channel-null.c
> index 75e3781507..4fafdb770d 100644
> --- a/io/channel-null.c
> +++ b/io/channel-null.c
> @@ -60,6 +60,7 @@ qio_channel_null_readv(QIOChannel *ioc,
> size_t niov,
> int **fds G_GNUC_UNUSED,
> size_t *nfds G_GNUC_UNUSED,
> + int flags,
> Error **errp)
> {
> QIOChannelNull *nioc = QIO_CHANNEL_NULL(ioc);
> diff --git a/io/channel-socket.c b/io/channel-socket.c
> index b76dca9cc1..a06b24766d 100644
> --- a/io/channel-socket.c
> +++ b/io/channel-socket.c
> @@ -406,6 +406,8 @@ qio_channel_socket_accept(QIOChannelSocket *ioc,
> }
> #endif /* WIN32 */
>
> + qio_channel_set_feature(QIO_CHANNEL(cioc), QIO_CHANNEL_FEATURE_READ_MSG_PEEK);
> +
> trace_qio_channel_socket_accept_complete(ioc, cioc, cioc->fd);
> return cioc;
>
> @@ -496,6 +498,7 @@ static ssize_t qio_channel_socket_readv(QIOChannel *ioc,
> size_t niov,
> int **fds,
> size_t *nfds,
> + int flags,
> Error **errp)
> {
> QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
> @@ -517,6 +520,10 @@ static ssize_t qio_channel_socket_readv(QIOChannel *ioc,
>
> }
>
> + if (flags & QIO_CHANNEL_READ_FLAG_MSG_PEEK) {
> + sflags |= MSG_PEEK;
> + }
> +
> retry:
> ret = recvmsg(sioc->fd, &msg, sflags);
> if (ret < 0) {
> @@ -624,11 +631,17 @@ static ssize_t qio_channel_socket_readv(QIOChannel *ioc,
> size_t niov,
> int **fds,
> size_t *nfds,
> + int flags,
> Error **errp)
> {
> QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
> ssize_t done = 0;
> ssize_t i;
> + int sflags = 0;
> +
> + if (flags & QIO_CHANNEL_READ_FLAG_MSG_PEEK) {
> + sflags |= MSG_PEEK;
> + }
>
> for (i = 0; i < niov; i++) {
> ssize_t ret;
> @@ -636,7 +649,7 @@ static ssize_t qio_channel_socket_readv(QIOChannel *ioc,
> ret = recv(sioc->fd,
> iov[i].iov_base,
> iov[i].iov_len,
> - 0);
> + sflags);
> if (ret < 0) {
> if (errno == EAGAIN) {
> if (done) {
> @@ -705,7 +718,6 @@ 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)
> diff --git a/io/channel-tls.c b/io/channel-tls.c
> index 4ce890a538..c730cb8ec5 100644
> --- a/io/channel-tls.c
> +++ b/io/channel-tls.c
> @@ -260,6 +260,7 @@ static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
> size_t niov,
> int **fds,
> size_t *nfds,
> + int flags,
> Error **errp)
> {
> QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
> diff --git a/io/channel-websock.c b/io/channel-websock.c
> index fb4932ade7..a12acc27cf 100644
> --- a/io/channel-websock.c
> +++ b/io/channel-websock.c
> @@ -1081,6 +1081,7 @@ static ssize_t qio_channel_websock_readv(QIOChannel *ioc,
> size_t niov,
> int **fds,
> size_t *nfds,
> + int flags,
> Error **errp)
> {
> QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
> diff --git a/io/channel.c b/io/channel.c
> index 0640941ac5..23c8752918 100644
> --- a/io/channel.c
> +++ b/io/channel.c
> @@ -52,6 +52,7 @@ ssize_t qio_channel_readv_full(QIOChannel *ioc,
> size_t niov,
> int **fds,
> size_t *nfds,
> + int flags,
> Error **errp)
> {
> QIOChannelClass *klass = QIO_CHANNEL_GET_CLASS(ioc);
> @@ -63,7 +64,14 @@ ssize_t qio_channel_readv_full(QIOChannel *ioc,
> return -1;
> }
>
> - return klass->io_readv(ioc, iov, niov, fds, nfds, errp);
> + if ((flags & QIO_CHANNEL_READ_FLAG_MSG_PEEK) &&
> + !qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_READ_MSG_PEEK)) {
> + error_setg_errno(errp, EINVAL,
> + "Channel does not support peek read");
> + return -1;
> + }
> +
> + return klass->io_readv(ioc, iov, niov, fds, nfds, flags, errp);
> }
>
>
> @@ -109,6 +117,37 @@ int qio_channel_readv_all_eof(QIOChannel *ioc,
> return qio_channel_readv_full_all_eof(ioc, iov, niov, NULL, NULL, errp);
> }
>
> +int qio_channel_readv_peek_all_eof(QIOChannel *ioc,
> + const struct iovec *iov,
> + size_t niov,
> + Error **errp)
> +{
> + ssize_t len = 0;
> + ssize_t total = iov_size(iov, niov);
> +
> + while (len < total) {
> + len = qio_channel_readv_full(ioc, iov, niov, NULL,
> + NULL, QIO_CHANNEL_READ_FLAG_MSG_PEEK, errp);
> +
> + if (len == QIO_CHANNEL_ERR_BLOCK) {
> + if (qemu_in_coroutine()) {
> + qio_channel_yield(ioc, G_IO_IN);
> + } else {
> + qio_channel_wait(ioc, G_IO_IN);
> + }
> + continue;
> + }
> + if (len == 0) {
> + return 0;
> + }
> + if (len < 0) {
> + return -1;
> + }
> + }
> +
> + return 1;
> +}
> +
> int qio_channel_readv_all(QIOChannel *ioc,
> const struct iovec *iov,
> size_t niov,
> @@ -117,6 +156,24 @@ int qio_channel_readv_all(QIOChannel *ioc,
> return qio_channel_readv_full_all(ioc, iov, niov, NULL, NULL, errp);
> }
>
> +int qio_channel_readv_peek_all(QIOChannel *ioc,
> + const struct iovec *iov,
> + size_t niov,
> + Error **errp)
> +{
> + int ret = qio_channel_readv_peek_all_eof(ioc, iov, niov, errp);
> +
> + if (ret == 0) {
> + error_setg(errp, "Unexpected end-of-file before all data were read");
> + return -1;
> + }
> + if (ret == 1) {
> + return 0;
> + }
> +
> + return ret;
> +}
> +
> int qio_channel_readv_full_all_eof(QIOChannel *ioc,
> const struct iovec *iov,
> size_t niov,
> @@ -146,7 +203,7 @@ int 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, errp);
> + local_nfds, 0, errp);
> if (len == QIO_CHANNEL_ERR_BLOCK) {
> if (qemu_in_coroutine()) {
> qio_channel_yield(ioc, G_IO_IN);
> @@ -284,7 +341,7 @@ ssize_t qio_channel_readv(QIOChannel *ioc,
> size_t niov,
> Error **errp)
> {
> - return qio_channel_readv_full(ioc, iov, niov, NULL, NULL, errp);
> + return qio_channel_readv_full(ioc, iov, niov, NULL, NULL, 0, errp);
> }
>
>
> @@ -303,7 +360,7 @@ ssize_t qio_channel_read(QIOChannel *ioc,
> Error **errp)
> {
> struct iovec iov = { .iov_base = buf, .iov_len = buflen };
> - return qio_channel_readv_full(ioc, &iov, 1, NULL, NULL, errp);
> + return qio_channel_readv_full(ioc, &iov, 1, NULL, NULL, 0, errp);
> }
>
>
> @@ -336,6 +393,14 @@ int qio_channel_read_all(QIOChannel *ioc,
> return qio_channel_readv_all(ioc, &iov, 1, errp);
> }
>
> +int qio_channel_read_peek_all(QIOChannel *ioc,
> + const char *buf,
> + size_t buflen,
> + Error **errp)
> +{
> + struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen };
> + return qio_channel_readv_peek_all(ioc, &iov, 1, errp);
> +}
>
> int qio_channel_write_all(QIOChannel *ioc,
> const char *buf,
> diff --git a/migration/channel-block.c b/migration/channel-block.c
> index c55c8c93ce..0b0deeb919 100644
> --- a/migration/channel-block.c
> +++ b/migration/channel-block.c
> @@ -53,6 +53,7 @@ qio_channel_block_readv(QIOChannel *ioc,
> size_t niov,
> int **fds,
> size_t *nfds,
> + int flags,
> Error **errp)
> {
> QIOChannelBlock *bioc = QIO_CHANNEL_BLOCK(ioc);
> diff --git a/scsi/qemu-pr-helper.c b/scsi/qemu-pr-helper.c
> index 196b78c00d..199227a556 100644
> --- a/scsi/qemu-pr-helper.c
> +++ b/scsi/qemu-pr-helper.c
> @@ -614,7 +614,7 @@ static int coroutine_fn prh_read(PRHelperClient *client, void *buf, int sz,
> iov.iov_base = buf;
> iov.iov_len = sz;
> n_read = qio_channel_readv_full(QIO_CHANNEL(client->ioc), &iov, 1,
> - &fds, &nfds, errp);
> + &fds, &nfds, 0, errp);
>
> if (n_read == QIO_CHANNEL_ERR_BLOCK) {
> qio_channel_yield(QIO_CHANNEL(client->ioc), G_IO_IN);
> diff --git a/tests/qtest/tpm-emu.c b/tests/qtest/tpm-emu.c
> index 2994d1cf42..3cf1acaf7d 100644
> --- a/tests/qtest/tpm-emu.c
> +++ b/tests/qtest/tpm-emu.c
> @@ -106,7 +106,7 @@ void *tpm_emu_ctrl_thread(void *data)
> int *pfd = NULL;
> size_t nfd = 0;
>
> - qio_channel_readv_full(ioc, &iov, 1, &pfd, &nfd, &error_abort);
> + qio_channel_readv_full(ioc, &iov, 1, &pfd, &nfd, 0, &error_abort);
> cmd = be32_to_cpu(cmd);
> g_assert_cmpint(cmd, ==, CMD_SET_DATAFD);
> g_assert_cmpint(nfd, ==, 1);
> diff --git a/tests/unit/test-io-channel-socket.c b/tests/unit/test-io-channel-socket.c
> index b36a5d972a..b964bb202d 100644
> --- a/tests/unit/test-io-channel-socket.c
> +++ b/tests/unit/test-io-channel-socket.c
> @@ -460,6 +460,7 @@ static void test_io_channel_unix_fd_pass(void)
> G_N_ELEMENTS(iorecv),
> &fdrecv,
> &nfdrecv,
> + 0,
> &error_abort);
>
> g_assert(nfdrecv == G_N_ELEMENTS(fdsend));
> diff --git a/util/vhost-user-server.c b/util/vhost-user-server.c
> index 232984ace6..145eb17c08 100644
> --- a/util/vhost-user-server.c
> +++ b/util/vhost-user-server.c
> @@ -116,7 +116,7 @@ vu_message_read(VuDev *vu_dev, int conn_fd, VhostUserMsg *vmsg)
> * qio_channel_readv_full may have short reads, keeping calling it
> * until getting VHOST_USER_HDR_SIZE or 0 bytes in total
> */
> - rc = qio_channel_readv_full(ioc, &iov, 1, &fds, &nfds, &local_err);
> + rc = qio_channel_readv_full(ioc, &iov, 1, &fds, &nfds, 0, &local_err);
> if (rc < 0) {
> if (rc == QIO_CHANNEL_ERR_BLOCK) {
> assert(local_err == NULL);
Sorry ignore this series, sent my mistake, there is another series tagged with V3.
prev parent reply other threads:[~2022-11-19 9:41 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-11-19 9:36 [PATCH 1/2] io: Add support for MSG_PEEK for socket channel manish.mishra
2022-11-19 9:36 ` [PATCH 2/2] migration: check magic value for deciding the mapping of channels manish.mishra
2022-11-19 9:36 ` manish.mishra
2022-11-19 9:36 ` [PATCH v3 1/2] io: Add support for MSG_PEEK for socket channel manish.mishra
2022-11-22 9:00 ` Daniel P. Berrangé
2022-11-22 9:08 ` manish.mishra
2022-11-22 9:29 ` Daniel P. Berrangé
2022-11-22 9:40 ` manish.mishra
2022-11-22 9:53 ` Daniel P. Berrangé
2022-11-22 10:13 ` manish.mishra
2022-11-22 10:31 ` Daniel P. Berrangé
2022-11-22 14:41 ` Peter Xu
2022-11-22 14:49 ` Daniel P. Berrangé
2022-11-22 15:31 ` manish.mishra
2022-11-22 16:10 ` Peter Xu
2022-11-22 16:29 ` Peter Xu
2022-11-22 16:33 ` Peter Xu
2022-11-22 16:42 ` manish.mishra
2022-11-22 17:16 ` Peter Xu
2022-11-22 17:31 ` Daniel P. Berrangé
2022-11-19 9:36 ` [PATCH v3 2/2] migration: check magic value for deciding the mapping of channels manish.mishra
2022-11-21 21:59 ` Peter Xu
2022-11-22 9:01 ` Daniel P. Berrangé
2022-11-19 9:40 ` manish.mishra [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=36c26e0c-cd1d-854f-f14d-e1935a84dae7@nutanix.com \
--to=manish.mishra@nutanix.com \
--cc=berrange@redhat.com \
--cc=dgilbert@redhat.com \
--cc=lsoaresp@redhat.com \
--cc=peterx@redhat.com \
--cc=prerna.saxena@nutanix.com \
--cc=qemu-devel@nongnu.org \
--cc=quintela@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).