qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Daniel P. Berrangé" <berrange@redhat.com>
To: Jagannathan Raman <jag.raman@oracle.com>
Cc: elena.ufimtseva@oracle.com, fam@euphon.net,
	swapnil.ingle@nutanix.com, john.g.johnson@oracle.com,
	qemu-devel@nongnu.org, kraxel@redhat.com, quintela@redhat.com,
	mst@redhat.com, armbru@redhat.com, kanth.ghatraju@oracle.com,
	felipe@nutanix.com, thuth@redhat.com, ehabkost@redhat.com,
	konrad.wilk@oracle.com, dgilbert@redhat.com,
	alex.williamson@redhat.com, stefanha@redhat.com,
	thanos.makatos@nutanix.com, kwolf@redhat.com, mreitz@redhat.com,
	ross.lagerwall@citrix.com, marcandre.lureau@gmail.com,
	pbonzini@redhat.com
Subject: Re: [PATCH v20 08/20] io: add qio_channel_readv_full_all_eof & qio_channel_readv_full_all helpers
Date: Mon, 25 Jan 2021 16:41:04 +0000	[thread overview]
Message-ID: <20210125164104.GA3538803@redhat.com> (raw)
In-Reply-To: <ac1c0900ed34c8bf4e93dd77507fc34169bb8ee4.1611081587.git.jag.raman@oracle.com>

On Tue, Jan 19, 2021 at 03:28:25PM -0500, Jagannathan Raman wrote:
> From: Elena Ufimtseva <elena.ufimtseva@oracle.com>
> 
> Adds qio_channel_readv_full_all_eof() and qio_channel_readv_full_all()
> to read both data and FDs. Refactors existing code to use these helpers.
> 
> Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
> Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
> Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
> ---
>  include/io/channel.h |  53 ++++++++++++++++++++++++++
>  io/channel.c         | 106 +++++++++++++++++++++++++++++++++++++++++----------
>  2 files changed, 138 insertions(+), 21 deletions(-)
> 
> diff --git a/include/io/channel.h b/include/io/channel.h
> index 19e76fc..8898897 100644
> --- a/include/io/channel.h
> +++ b/include/io/channel.h
> @@ -778,6 +778,59 @@ void qio_channel_set_aio_fd_handler(QIOChannel *ioc,
>                                      void *opaque);
>  
>  /**
> + * qio_channel_readv_full_all_eof:
> + * @ioc: the channel object
> + * @iov: the array of memory regions to read data to
> + * @niov: the length of the @iov array
> + * @fds: an array of file handles to read
> + * @nfds: number of file handles in @fds
> + * @errp: pointer to a NULL-initialized error object
> + *
> + *
> + * Performs same function as qio_channel_readv_all_eof.
> + * Additionally, attempts to read file descriptors shared
> + * over the channel. The function will wait for all
> + * requested data to be read, yielding from the current
> + * coroutine if required. data refers to both file
> + * descriptors and the iovs.
> + *
> + * Returns: 1 if all bytes were read, 0 if end-of-file
> + *          occurs without data, or -1 on error
> + */
> +
> +int qio_channel_readv_full_all_eof(QIOChannel *ioc,
> +                                   const struct iovec *iov,
> +                                   size_t niov,
> +                                   int **fds, size_t *nfds,
> +                                   Error **errp);
> +
> +/**
> + * qio_channel_readv_full_all:
> + * @ioc: the channel object
> + * @iov: the array of memory regions to read data to
> + * @niov: the length of the @iov array
> + * @fds: an array of file handles to read
> + * @nfds: number of file handles in @fds
> + * @errp: pointer to a NULL-initialized error object
> + *
> + *
> + * Performs same function as qio_channel_readv_all_eof.
> + * Additionally, attempts to read file descriptors shared
> + * over the channel. The function will wait for all
> + * requested data to be read, yielding from the current
> + * coroutine if required. data refers to both file
> + * descriptors and the iovs.
> + *
> + * Returns: 0 if all bytes were read, or -1 on error
> + */
> +
> +int qio_channel_readv_full_all(QIOChannel *ioc,
> +                               const struct iovec *iov,
> +                               size_t niov,
> +                               int **fds, size_t *nfds,
> +                               Error **errp);
> +
> +/**
>   * qio_channel_writev_full_all:
>   * @ioc: the channel object
>   * @iov: the array of memory regions to write data from
> diff --git a/io/channel.c b/io/channel.c
> index 0d4b8b5..b12db9d 100644
> --- a/io/channel.c
> +++ b/io/channel.c


> +int qio_channel_readv_full_all_eof(QIOChannel *ioc,
> +                                   const struct iovec *iov,
> +                                   size_t niov,
> +                                   int **fds, size_t *nfds,
> +                                   Error **errp)
> +{
>      int ret = -1;
>      struct iovec *local_iov = g_new(struct iovec, niov);
>      struct iovec *local_iov_head = local_iov;
>      unsigned int nlocal_iov = niov;
> +    int **local_fds = fds;
> +    size_t *local_nfds = nfds;
>      bool partial = false;
>  
> +    if (nfds) {
> +        *nfds = 0;
> +    }
> +
> +    if (fds) {
> +        *fds = NULL;
> +    }
> +
>      nlocal_iov = iov_copy(local_iov, nlocal_iov,
>                            iov, niov,
>                            0, iov_size(iov, niov));
>  
> -    while (nlocal_iov > 0) {
> +    while ((nlocal_iov > 0) || local_fds) {
>          ssize_t len;
> -        len = qio_channel_readv(ioc, local_iov, nlocal_iov, errp);
> +        len = qio_channel_readv_full(ioc, local_iov, nlocal_iov, local_fds,
> +                                     local_nfds, errp);
>          if (len == QIO_CHANNEL_ERR_BLOCK) {
>              if (qemu_in_coroutine()) {
>                  qio_channel_yield(ioc, G_IO_IN);
> @@ -112,20 +140,53 @@ int qio_channel_readv_all_eof(QIOChannel *ioc,
>                  qio_channel_wait(ioc, G_IO_IN);
>              }
>              continue;
> -        } else if (len < 0) {
> -            goto cleanup;
> -        } else if (len == 0) {
> -            if (partial) {
> -                error_setg(errp,
> -                           "Unexpected end-of-file before all bytes were read");
> -            } else {
> -                ret = 0;
> +        }
> +
> +        if (len <= 0) {
> +            size_t fd_idx;
> +
> +            if (!len && !niov && (nfds && *nfds)) {
> +                break;
> +            }
> +
> +            if (!partial && (!nfds || !(*nfds))) {
> +                ret = len;
> +                goto cleanup;
>              }
> +
> +            error_prepend(errp,
> +                          "Unexpected end-of-file before all data were read.");
> +
> +            if (!nfds || !(*nfds)) {
> +                goto cleanup;
> +            }

I'm finding it really hard to understand what scenario each of
these three if() tests is validating, so can't be confident that
we've dealt with the failure cases correctly.

In the  len < 0 case, we shouldn't be reporting the "unexpected end-of-file"
message at all, as it won't be and end of file - its some other failure
condition.

In the len == 0 case, we should be using error_setg not error_prepend
AFAIK.

> +
> +            /*
> +             * If (len < 0) and fds are returned, it's not clear if the
> +             * returned fds are valid to be closed. Just free'ing the
> +             * allocated memory for fds in this case
> +             */
> +            fd_idx = *nfds;
> +            while (fd_idx && !len) {
> +                close((*fds)[fd_idx - 1]);
> +                fd_idx--;
> +            }

I'm not sure ignoring the len < 0 case is correct. The first time we
call qio_channel_readv_full(), we can receive some FDs, either with
or without some data bytes.

The second time we call qio_channel_readv_full we can get len == -1
and so need to return an error. We must close the FDs we received on
the previous iteration at this point.



> +
> +            g_free(*fds);
> +            *fds = NULL;
> +            *nfds = 0;
> +
>              goto cleanup;
>          }

I'm thinking the above error handling would be clearer if we could
separate out the len == 0 case from the len == -1 case initially.

eg, would this logic do what we need:

        if (len == 0) {
            if (local_nfds && *local_nfds) {
                /* got some FDs, but not data yet. This isn't an EOF
                 * scenario (yet), so carry on to try to read data
                 * on next loop iteration */
            } else if (!partial) {
                /* no fds and no data, must be an expected EOF */
                ret = 0;
                goto cleanup;
            } else {
                len = -1;
                error_setg(errp,
                           "Unexpected end-of-file before all data were read.");
                /* fallthrough into len < 0 handling now */
            }
        }

        if (len < 0) {
            /* Close any FDs we previously received */
            if (nfds && fds) {
                size_t i;
                for (i = 0; nfds && i < *nfds; i++) {
                    close((*fds)[i]);
                }

                g_free(*fds);
                *fds = NULL;
                *nfds = 0;
            }

            goto cleanup;
        }

>  
>          partial = true;
> -        iov_discard_front(&local_iov, &nlocal_iov, len);
> +
> +        if (nlocal_iov) {
> +            iov_discard_front(&local_iov, &nlocal_iov, len);
> +        }
> +
> +        local_fds = NULL;
> +        local_nfds = NULL;
>      }
>  
>      ret = 1;
> @@ -135,20 +196,23 @@ int qio_channel_readv_all_eof(QIOChannel *ioc,
>      return ret;
>  }
>  
> -int qio_channel_readv_all(QIOChannel *ioc,
> -                          const struct iovec *iov,
> -                          size_t niov,
> -                          Error **errp)
> +int qio_channel_readv_full_all(QIOChannel *ioc,
> +                               const struct iovec *iov,
> +                               size_t niov,
> +                               int **fds, size_t *nfds,
> +                               Error **errp)
>  {
> -    int ret = qio_channel_readv_all_eof(ioc, iov, niov, errp);
> +    int ret = qio_channel_readv_full_all_eof(ioc, iov, niov, fds, nfds, errp);
>  
>      if (ret == 0) {
> -        ret = -1;
> -        error_setg(errp,
> -                   "Unexpected end-of-file before all bytes were read");
> -    } else if (ret == 1) {
> -        ret = 0;
> +        error_prepend(errp,
> +                      "Unexpected end-of-file before all data were read.");
> +        return -1;
>      }
> +    if (ret == 1) {
> +        return 0;
> +    }
> +
>      return ret;
>  }
>  
> -- 
> 1.8.3.1
> 

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



  reply	other threads:[~2021-01-25 16:43 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-19 20:28 [PATCH v20 00/20] Initial support for multi-process Qemu Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 01/20] multi-process: add the concept description to docs/devel/qemu-multiprocess Jagannathan Raman
2021-01-25 16:57   ` Cédric Le Goater
2021-01-27 16:47     ` Jag Raman
2021-01-28  9:53       ` Thanos Makatos
2021-01-19 20:28 ` [PATCH v20 02/20] multi-process: add configure and usage information Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 03/20] memory: alloc RAM from file at offset Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 04/20] multi-process: Add config option for multi-process QEMU Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 05/20] multi-process: setup PCI host bridge for remote device Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 06/20] multi-process: setup a machine object for remote device process Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 07/20] io: add qio_channel_writev_full_all helper Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 08/20] io: add qio_channel_readv_full_all_eof & qio_channel_readv_full_all helpers Jagannathan Raman
2021-01-25 16:41   ` Daniel P. Berrangé [this message]
2021-01-19 20:28 ` [PATCH v20 09/20] multi-process: define MPQemuMsg format and transmission functions Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 10/20] multi-process: Initialize message handler in remote device Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 11/20] multi-process: Associate fd of a PCIDevice with its object Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 12/20] multi-process: setup memory manager for remote device Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 13/20] multi-process: introduce proxy object Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 14/20] multi-process: add proxy communication functions Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 15/20] multi-process: Forward PCI config space acceses to the remote process Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 16/20] multi-process: PCI BAR read/write handling for proxy & remote endpoints Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 17/20] multi-process: Synchronize remote memory Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 18/20] multi-process: create IOHUB object to handle irq Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 19/20] multi-process: Retrieve PCI info from remote process Jagannathan Raman
2021-01-19 20:28 ` [PATCH v20 20/20] multi-process: perform device reset in the " Jagannathan Raman
2021-01-21 17:07 ` [PATCH v20 00/20] Initial support for multi-process Qemu Stefan Hajnoczi
2021-01-21 17:37   ` Jag Raman

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=20210125164104.GA3538803@redhat.com \
    --to=berrange@redhat.com \
    --cc=alex.williamson@redhat.com \
    --cc=armbru@redhat.com \
    --cc=dgilbert@redhat.com \
    --cc=ehabkost@redhat.com \
    --cc=elena.ufimtseva@oracle.com \
    --cc=fam@euphon.net \
    --cc=felipe@nutanix.com \
    --cc=jag.raman@oracle.com \
    --cc=john.g.johnson@oracle.com \
    --cc=kanth.ghatraju@oracle.com \
    --cc=konrad.wilk@oracle.com \
    --cc=kraxel@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=marcandre.lureau@gmail.com \
    --cc=mreitz@redhat.com \
    --cc=mst@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=quintela@redhat.com \
    --cc=ross.lagerwall@citrix.com \
    --cc=stefanha@redhat.com \
    --cc=swapnil.ingle@nutanix.com \
    --cc=thanos.makatos@nutanix.com \
    --cc=thuth@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).