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
{