All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Daniel P. Berrangé via qemu development" <qemu-devel@nongnu.org>
To: Junjie Cao <junjie.cao@intel.com>
Cc: qemu-devel@nongnu.org, peterx@redhat.com, farosas@suse.de
Subject: Re: [PATCH v2 1/3] io/channel: introduce qio_channel_pread{v, }_all() and preadv_all_eof()
Date: Tue, 24 Mar 2026 10:51:53 +0000	[thread overview]
Message-ID: <acJsyXqcMfzjHz58@redhat.com> (raw)
In-Reply-To: <20260318140113.434-2-junjie.cao@intel.com>

On Wed, Mar 18, 2026 at 10:01:11PM +0800, Junjie Cao wrote:
> qio_channel_pread() and qio_channel_preadv() perform a single read
> and may return a short result.  Callers that need all bytes currently
> have to open-code a retry loop or simply treat a short read as an
> error.
> 
> Introduce three new helpers following the existing read_all / readv_all
> pattern:
> 
>   qio_channel_preadv_all_eof()  – retry loop; returns 1 on success,
>                                    0 on clean EOF, -1 on error.
>   qio_channel_preadv_all()      – wraps _eof; treats early EOF as
>                                    error; returns 0 / -1.
>   qio_channel_pread_all()       – single-buffer convenience wrapper
>                                    around preadv_all().
> 
> These advance the file offset internally after each partial read, so
> callers only need a single call.  All three are marked
> coroutine_mixed_fn, consistent with the existing _all helpers.
> 
> Suggested-by: Peter Xu <peterx@redhat.com>
> Signed-off-by: Junjie Cao <junjie.cao@intel.com>
> ---
>  include/io/channel.h | 63 ++++++++++++++++++++++++++++++++
>  io/channel.c         | 85 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 148 insertions(+)

So currently we have:

   qio_channel_read
   qio_channel_read_all
   qio_channel_read_all_eof

   qio_channel_readv
   qio_channel_readv_all
   qio_channel_readv_all_eof

   qio_channel_readv_full
   qio_channel_readv_full_all
   qio_channel_readv_full_all_eof

   qio_channel_pread
   qio_channel_preadv

The obvious gaps in this API design pattern are

   qio_channel_pread_all
   qio_channel_pread_all_eof
   qio_channel_preadv_all
   qio_channel_preadv_all_eof

Your patch is fixing 3 of those 4 gaps. Can you also ensure
it adds qio_channel_pread_all_eof so we complete the set.


On the write side we have

   qio_channel_write
   qio_channel_write_all

   qio_channel_writev
   qio_channel_writev_all

   qio_channel_writev_full
   qio_channel_writev_full_all

   qio_channel_pwrite
   qio_channel_pwritev

Thus we're missing

   qio_channel_pwrite_all
   qio_channel_pwritev_all

Your patch only adds read variants, can you add the corresponding
write variants too.

The write variants can be a separate commit from the read
variants.

> diff --git a/include/io/channel.h b/include/io/channel.h
> index 1b02350437..d5b14c8c77 100644
> --- a/include/io/channel.h
> +++ b/include/io/channel.h
> @@ -634,6 +634,69 @@ ssize_t qio_channel_preadv(QIOChannel *ioc, const struct iovec *iov,
>  ssize_t qio_channel_pread(QIOChannel *ioc, void *buf, size_t buflen,
>                            off_t offset, Error **errp);
>  
> +/**
> + * qio_channel_preadv_all_eof:
> + * @ioc: the channel object
> + * @iov: the array of memory regions to read data into
> + * @niov: the length of the @iov array
> + * @offset: the starting offset in the channel to read from
> + * @errp: pointer to a NULL-initialized error object
> + *
> + * Reads data contiguously from the channel into @iov starting at
> + * @offset, retrying on short reads until all requested bytes have
> + * been read.  The offset is advanced internally after each partial
> + * read.
> + *
> + * Returns: 1 if all bytes were read, 0 if no data could be read
> + *          before encountering end-of-file, or -1 on error

Keep the descriptive text matching the other APIs as closely
as possible. eg

 * Reads @iov, 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 immediately it is not an
 * error, but if it occurs after data has been read it will return
 * an error rather than a short-read. Otherwise behaves as
 * qio_channel_preadv().
 *
 * Returns: 1 if all bytes were read, 0 if end-of-file occurs
 *          without data, or -1 on error


And similarly copy the docs for the other APIs as closely
as possible.

> + */
> +int coroutine_mixed_fn qio_channel_preadv_all_eof(QIOChannel *ioc,
> +                                                  const struct iovec *iov,
> +                                                  size_t niov,
> +                                                  off_t offset,
> +                                                  Error **errp);
> +
> +/**
> + * qio_channel_preadv_all:
> + * @ioc: the channel object
> + * @iov: the array of memory regions to read data into
> + * @niov: the length of the @iov array
> + * @offset: the starting offset in the channel to read from
> + * @errp: pointer to a NULL-initialized error object
> + *
> + * Reads data contiguously from the channel into @iov starting at
> + * @offset, retrying on short reads until all requested bytes have
> + * been read.  Unlike qio_channel_preadv_all_eof(), end-of-file
> + * before all data has been read is treated as an error.
> + *
> + * Returns: 0 if all bytes were read, or -1 on error
> + */
> +int coroutine_mixed_fn qio_channel_preadv_all(QIOChannel *ioc,
> +                                              const struct iovec *iov,
> +                                              size_t niov,
> +                                              off_t offset,
> +                                              Error **errp);
> +
> +/**
> + * qio_channel_pread_all:
> + * @ioc: the channel object
> + * @buf: the memory region to read data into
> + * @buflen: the number of bytes to read into @buf
> + * @offset: the starting offset in the channel to read from
> + * @errp: pointer to a NULL-initialized error object
> + *
> + * Reads @buflen bytes contiguously from the channel at @offset
> + * into @buf, retrying on short reads.  End-of-file before all data
> + * has been read is treated as an error.
> + *
> + * Returns: 0 if all bytes were read, or -1 on error
> + */
> +int coroutine_mixed_fn qio_channel_pread_all(QIOChannel *ioc,
> +                                             void *buf,
> +                                             size_t buflen,
> +                                             off_t offset,
> +                                             Error **errp);
> +
>  /**
>   * qio_channel_shutdown:
>   * @ioc: the channel object
> diff --git a/io/channel.c b/io/channel.c
> index cc02d997a4..e18c40aa0b 100644
> --- a/io/channel.c
> +++ b/io/channel.c
> @@ -507,6 +507,91 @@ ssize_t qio_channel_pread(QIOChannel *ioc, void *buf, size_t buflen,
>      return qio_channel_preadv(ioc, &iov, 1, offset, errp);
>  }
>  
> +int coroutine_mixed_fn qio_channel_preadv_all_eof(QIOChannel *ioc,
> +                                                  const struct iovec *iov,
> +                                                  size_t niov,
> +                                                  off_t offset,
> +                                                  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;
> +    bool partial = false;
> +
> +    nlocal_iov = iov_copy(local_iov, nlocal_iov,
> +                          iov, niov,
> +                          0, iov_size(iov, niov));
> +
> +    while (nlocal_iov > 0) {
> +        ssize_t len;
> +        len = qio_channel_preadv(ioc, local_iov, nlocal_iov, offset, errp);
> +
> +        if (len == QIO_CHANNEL_ERR_BLOCK) {
> +            qio_channel_wait_cond(ioc, G_IO_IN);
> +            continue;
> +        }
> +
> +        if (len == 0) {
> +            if (!partial) {
> +                ret = 0;
> +                goto cleanup;
> +            }
> +            error_setg(errp,
> +                       "Unexpected end-of-file before all data were read");
> +            goto cleanup;
> +        }
> +
> +        if (len < 0) {
> +            goto cleanup;
> +        }
> +
> +        partial = true;
> +        offset += len;
> +        iov_discard_front(&local_iov, &nlocal_iov, len);
> +    }
> +
> +    ret = 1;
> +
> + cleanup:
> +    g_free(local_iov_head);
> +    return ret;
> +}
> +
> +int coroutine_mixed_fn qio_channel_preadv_all(QIOChannel *ioc,
> +                                              const struct iovec *iov,
> +                                              size_t niov,
> +                                              off_t offset,
> +                                              Error **errp)
> +{
> +    int ret = qio_channel_preadv_all_eof(ioc, iov, niov, offset, 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 coroutine_mixed_fn qio_channel_pread_all(QIOChannel *ioc,
> +                                             void *buf,
> +                                             size_t buflen,
> +                                             off_t offset,
> +                                             Error **errp)
> +{
> +    struct iovec iov = {
> +        .iov_base = buf,
> +        .iov_len = buflen
> +    };
> +
> +    return qio_channel_preadv_all(ioc, &iov, 1, offset, errp);
> +}
> +
>  int qio_channel_shutdown(QIOChannel *ioc,
>                           QIOChannelShutdown how,
>                           Error **errp)
> -- 
> 2.43.0
> 

With regards,
Daniel
-- 
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|



  reply	other threads:[~2026-03-24 10:52 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-16  8:46 [PATCH] migration/file: fix type mismatch and NULL deref in multifd_file_recv_data Junjie Cao
2026-03-16 20:41 ` Peter Xu
2026-03-17  8:58   ` Daniel P. Berrangé
2026-03-18 14:01 ` [PATCH v2 0/3] " Junjie Cao
2026-03-18 14:01   ` [PATCH v2 1/3] io/channel: introduce qio_channel_pread{v, }_all() and preadv_all_eof() Junjie Cao
2026-03-24 10:51     ` Daniel P. Berrangé via qemu development [this message]
2026-03-18 14:01   ` [PATCH v2 2/3] migration/file: fix type mismatch and NULL deref in multifd_file_recv_data Junjie Cao
2026-03-24 10:53     ` Daniel P. Berrangé
2026-03-18 14:01   ` [PATCH v2 3/3] tests/unit: add pread_all and preadv_all tests for io channel file Junjie Cao
2026-03-24  8:27   ` [PATCH v2 0/3] migration/file: fix type mismatch and NULL deref in multifd_file_recv_data Junjie Cao
2026-03-24 10:54     ` Daniel P. Berrangé
2026-03-26 15:21       ` Peter Xu

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=acJsyXqcMfzjHz58@redhat.com \
    --to=qemu-devel@nongnu.org \
    --cc=berrange@redhat.com \
    --cc=farosas@suse.de \
    --cc=junjie.cao@intel.com \
    --cc=peterx@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.