@samitouri / QOSamiQemu / commits / 40bf7bbcf4

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

Add positioned write helpers that retry on short writes, matching the pread_all family from the previous patch. qio_channel_pwritev_all() -- retry loop; returns 0 on success, -1 on error. qio_channel_pwrite_all() -- single-buffer convenience wrapper. Signed-off-by: Junjie Cao <junjie.cao@intel.com> Reviewed-by: Fabiano Rosas <farosas@suse.de> Link: https://lore.kernel.org/qemu-devel/20260413214549.926435-3-junjie.cao@intel.com Signed-off-by: Fabiano Rosas <farosas@suse.de>

Junjie Cao committed Apr 14, 2026 at 05:45 UTC 40bf7bbcf47493b766a567aff937a8271bb789e3
2 files changed +89
include/io/channel.h
+41
@@ -598,6 +598,47 @@ ssize_t qio_channel_pwritev(QIOChannel *ioc, const struct iovec *iov,
598 ssize_t qio_channel_pwrite(QIOChannel *ioc, void *buf, size_t buflen,
599 off_t offset, Error **errp);
600
601 +/**
602 + * qio_channel_pwritev_all:
603 + * @ioc: the channel object
604 + * @iov: the array of memory regions to write data from
605 + * @niov: the length of the @iov array
606 + * @offset: the starting offset in the channel to write to
607 + * @errp: pointer to a NULL-initialized error object
608 + *
609 + * Writes @iov, possibly blocking or (if the channel is non-blocking)
610 + * yielding from the current coroutine multiple times until the entire
611 + * content is written. Otherwise behaves as qio_channel_pwritev().
612 + *
613 + * Returns: 0 if all bytes were written, or -1 on error
614 + */
615 +int coroutine_mixed_fn qio_channel_pwritev_all(QIOChannel *ioc,
616 + const struct iovec *iov,
617 + size_t niov,
618 + off_t offset,
619 + Error **errp);
620 +
621 +/**
622 + * qio_channel_pwrite_all:
623 + * @ioc: the channel object
624 + * @buf: the memory region to write data from
625 + * @buflen: the number of bytes to write from @buf
626 + * @offset: the starting offset in the channel to write to
627 + * @errp: pointer to a NULL-initialized error object
628 + *
629 + * Writes @buflen bytes from @buf, possibly blocking or (if the
630 + * channel is non-blocking) yielding from the current coroutine
631 + * multiple times until the entire content is written. Otherwise
632 + * behaves as qio_channel_pwrite().
633 + *
634 + * Returns: 0 if all bytes were written, or -1 on error
635 + */
636 +int coroutine_mixed_fn qio_channel_pwrite_all(QIOChannel *ioc,
637 + const void *buf,
638 + size_t buflen,
639 + off_t offset,
640 + Error **errp);
641 +
642 /**
643 * qio_channel_preadv
644 * @ioc: the channel object
io/channel.c
+48
@@ -478,6 +478,54 @@ ssize_t qio_channel_pwrite(QIOChannel *ioc, void *buf, size_t buflen,
478 return qio_channel_pwritev(ioc, &iov, 1, offset, errp);
479 }
480
481 +int coroutine_mixed_fn qio_channel_pwritev_all(QIOChannel *ioc,
482 + const struct iovec *iov,
483 + size_t niov,
484 + off_t offset,
485 + Error **errp)
486 +{
487 + int ret = -1;
488 + struct iovec *local_iov = g_new(struct iovec, niov);
489 + struct iovec *local_iov_head = local_iov;
490 + unsigned int nlocal_iov = niov;
491 +
492 + nlocal_iov = iov_copy(local_iov, nlocal_iov,
493 + iov, niov,
494 + 0, iov_size(iov, niov));
495 +
496 + while (nlocal_iov > 0) {
497 + ssize_t len;
498 +
499 + len = qio_channel_pwritev(ioc, local_iov, nlocal_iov, offset, errp);
500 +
501 + if (len == QIO_CHANNEL_ERR_BLOCK) {
502 + qio_channel_wait_cond(ioc, G_IO_OUT);
503 + continue;
504 + }
505 + if (len < 0) {
506 + goto cleanup;
507 + }
508 +
509 + offset += len;
510 + iov_discard_front(&local_iov, &nlocal_iov, len);
511 + }
512 +
513 + ret = 0;
514 + cleanup:
515 + g_free(local_iov_head);
516 + return ret;
517 +}
518 +
519 +int coroutine_mixed_fn qio_channel_pwrite_all(QIOChannel *ioc,
520 + const void *buf,
521 + size_t buflen,
522 + off_t offset,
523 + Error **errp)
524 +{
525 + struct iovec iov = { .iov_base = (char *)buf, .iov_len = buflen };
526 + return qio_channel_pwritev_all(ioc, &iov, 1, offset, errp);
527 +}
528 +
529 ssize_t qio_channel_preadv(QIOChannel *ioc, const struct iovec *iov,
530 size_t niov, off_t offset, Error **errp)
531 {