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 :|
next prev parent 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.