@samitouri / QOSamiQemu / commits / 2dd53f732b

io/channel: introduce qio_channel_pread{v, }_all{, _eof}()

qio_channel_pread() and qio_channel_preadv() perform a single positioned 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 four 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_eof() -- single-buffer convenience wrapper around preadv_all_eof(). qio_channel_pread_all() -- single-buffer convenience wrapper around preadv_all(). These advance the file offset internally after each partial read. All four 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> Reviewed-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Acked-by: Daniel P. Berrangé <berrange@redhat.com> Link: https://lore.kernel.org/qemu-devel/20260413214549.926435-2-junjie.cao@intel.com Signed-off-by: Fabiano Rosas <farosas@suse.de>

Junjie Cao committed Apr 14, 2026 at 05:45 UTC 2dd53f732b39c683064cc22ef040a1ece94e5e7f
2 files changed +183
include/io/channel.h
+92
@@ -634,6 +634,98 @@ ssize_t qio_channel_preadv(QIOChannel *ioc, const struct iovec *iov,
634 ssize_t qio_channel_pread(QIOChannel *ioc, void *buf, size_t buflen,
635 off_t offset, Error **errp);
636
637 +/**
638 + * qio_channel_preadv_all_eof:
639 + * @ioc: the channel object
640 + * @iov: the array of memory regions to read data into
641 + * @niov: the length of the @iov array
642 + * @offset: the starting offset in the channel to read from
643 + * @errp: pointer to a NULL-initialized error object
644 + *
645 + * Reads @iov, possibly blocking or (if the channel is non-blocking)
646 + * yielding from the current coroutine multiple times until the entire
647 + * content is read. If end-of-file occurs immediately it is not an
648 + * error, but if it occurs after data has been read it will return
649 + * an error rather than a short-read. Otherwise behaves as
650 + * qio_channel_preadv().
651 + *
652 + * Returns: 1 if all bytes were read, 0 if end-of-file occurs
653 + * without data, or -1 on error
654 + */
655 +int coroutine_mixed_fn qio_channel_preadv_all_eof(QIOChannel *ioc,
656 + const struct iovec *iov,
657 + size_t niov,
658 + off_t offset,
659 + Error **errp);
660 +
661 +/**
662 + * qio_channel_preadv_all:
663 + * @ioc: the channel object
664 + * @iov: the array of memory regions to read data into
665 + * @niov: the length of the @iov array
666 + * @offset: the starting offset in the channel to read from
667 + * @errp: pointer to a NULL-initialized error object
668 + *
669 + * Reads @iov, possibly blocking or (if the channel is non-blocking)
670 + * yielding from the current coroutine multiple times until the entire
671 + * content is read. If end-of-file occurs before all requested data
672 + * has been read, an error will be reported. Otherwise behaves as
673 + * qio_channel_preadv().
674 + *
675 + * Returns: 0 if all bytes were read, or -1 on error
676 + */
677 +int coroutine_mixed_fn qio_channel_preadv_all(QIOChannel *ioc,
678 + const struct iovec *iov,
679 + size_t niov,
680 + off_t offset,
681 + Error **errp);
682 +
683 +/**
684 + * qio_channel_pread_all_eof:
685 + * @ioc: the channel object
686 + * @buf: the memory region to read data into
687 + * @buflen: the number of bytes to read into @buf
688 + * @offset: the starting offset in the channel to read from
689 + * @errp: pointer to a NULL-initialized error object
690 + *
691 + * Reads @buflen bytes, possibly blocking or (if the channel is
692 + * non-blocking) yielding from the current coroutine multiple times
693 + * until the entire content is read. If end-of-file occurs
694 + * immediately it is not an error, but if it occurs after data has
695 + * been read it will return an error rather than a short-read.
696 + * Otherwise behaves as qio_channel_pread().
697 + *
698 + * Returns: 1 if all bytes were read, 0 if end-of-file occurs
699 + * without data, or -1 on error
700 + */
701 +int coroutine_mixed_fn qio_channel_pread_all_eof(QIOChannel *ioc,
702 + void *buf,
703 + size_t buflen,
704 + off_t offset,
705 + Error **errp);
706 +
707 +/**
708 + * qio_channel_pread_all:
709 + * @ioc: the channel object
710 + * @buf: the memory region to read data into
711 + * @buflen: the number of bytes to read into @buf
712 + * @offset: the starting offset in the channel to read from
713 + * @errp: pointer to a NULL-initialized error object
714 + *
715 + * Reads @buflen bytes, possibly blocking or (if the channel is
716 + * non-blocking) yielding from the current coroutine multiple times
717 + * until the entire content is read. If end-of-file occurs before
718 + * all requested data has been read, an error will be reported.
719 + * Otherwise behaves as qio_channel_pread().
720 + *
721 + * Returns: 0 if all bytes were read, or -1 on error
722 + */
723 +int coroutine_mixed_fn qio_channel_pread_all(QIOChannel *ioc,
724 + void *buf,
725 + size_t buflen,
726 + off_t offset,
727 + Error **errp);
728 +
729 /**
730 * qio_channel_shutdown:
731 * @ioc: the channel object
io/channel.c
+91
@@ -507,6 +507,97 @@ ssize_t qio_channel_pread(QIOChannel *ioc, void *buf, size_t buflen,
507 return qio_channel_preadv(ioc, &iov, 1, offset, errp);
508 }
509
510 +int coroutine_mixed_fn qio_channel_preadv_all_eof(QIOChannel *ioc,
511 + const struct iovec *iov,
512 + size_t niov,
513 + off_t offset,
514 + Error **errp)
515 +{
516 + int ret = -1;
517 + struct iovec *local_iov = g_new(struct iovec, niov);
518 + struct iovec *local_iov_head = local_iov;
519 + unsigned int nlocal_iov = niov;
520 + bool partial = false;
521 +
522 + nlocal_iov = iov_copy(local_iov, nlocal_iov,
523 + iov, niov,
524 + 0, iov_size(iov, niov));
525 +
526 + while (nlocal_iov > 0) {
527 + ssize_t len;
528 + len = qio_channel_preadv(ioc, local_iov, nlocal_iov, offset, errp);
529 +
530 + if (len == QIO_CHANNEL_ERR_BLOCK) {
531 + qio_channel_wait_cond(ioc, G_IO_IN);
532 + continue;
533 + }
534 +
535 + if (len == 0) {
536 + if (!partial) {
537 + ret = 0;
538 + goto cleanup;
539 + }
540 + error_setg(errp,
541 + "Unexpected end-of-file before all data were read");
542 + goto cleanup;
543 + }
544 +
545 + if (len < 0) {
546 + goto cleanup;
547 + }
548 +
549 + partial = true;
550 + offset += len;
551 + iov_discard_front(&local_iov, &nlocal_iov, len);
552 + }
553 +
554 + ret = 1;
555 +
556 + cleanup:
557 + g_free(local_iov_head);
558 + return ret;
559 +}
560 +
561 +int coroutine_mixed_fn qio_channel_preadv_all(QIOChannel *ioc,
562 + const struct iovec *iov,
563 + size_t niov,
564 + off_t offset,
565 + Error **errp)
566 +{
567 + int ret = qio_channel_preadv_all_eof(ioc, iov, niov, offset, errp);
568 +
569 + if (ret == 0) {
570 + error_setg(errp,
571 + "Unexpected end-of-file before all data were read");
572 + return -1;
573 + }
574 + if (ret == 1) {
575 + return 0;
576 + }
577 +
578 + return ret;
579 +}
580 +
581 +int coroutine_mixed_fn qio_channel_pread_all_eof(QIOChannel *ioc,
582 + void *buf,
583 + size_t buflen,
584 + off_t offset,
585 + Error **errp)
586 +{
587 + struct iovec iov = { .iov_base = buf, .iov_len = buflen };
588 + return qio_channel_preadv_all_eof(ioc, &iov, 1, offset, errp);
589 +}
590 +
591 +int coroutine_mixed_fn qio_channel_pread_all(QIOChannel *ioc,
592 + void *buf,
593 + size_t buflen,
594 + off_t offset,
595 + Error **errp)
596 +{
597 + struct iovec iov = { .iov_base = buf, .iov_len = buflen };
598 + return qio_channel_preadv_all(ioc, &iov, 1, offset, errp);
599 +}
600 +
601 int qio_channel_shutdown(QIOChannel *ioc,
602 QIOChannelShutdown how,
603 Error **errp)