io: invert the return semantics of qio_channel_flush

With the kernel's zerocopy notification mechanism, the caller can
determine whether
 * All syscalls successfully used zero copy
 * At least one syscall failed to use zero copy

But, as of now QEMU's IO channel flush function semantics are like
 * 1 => all syscalls failed to use zero copy
 * 0 => at least one syscall successfully used zero copy

This is not aligned with what the kernel reports, and ends up reporting
false negatives for cases like when there's just a single successful
zerocopy amongst a collection of deferred zero-copies during a flush.

Fix this by inverting the return semantics of the IO flush function.

Suggested-by: Peter Xu <peterx@redhat.com>
Suggested-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Tejus GK <tejus.gk@nutanix.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Tejus GK
2026-03-20 08:39:41 +00:00
committed by Daniel P. Berrangé
parent 3f129ea545
commit 2a092db9cb
3 changed files with 11 additions and 15 deletions

View File

@@ -50,11 +50,7 @@ struct QIOChannelSocket {
ssize_t zero_copy_queued; ssize_t zero_copy_queued;
ssize_t zero_copy_sent; ssize_t zero_copy_sent;
bool blocking; bool blocking;
/** bool zero_copy_fallback;
* This flag indicates whether any new data was successfully sent with
* zerocopy since the last qio_channel_socket_flush() call.
*/
bool new_zero_copy_sent_success;
}; };

View File

@@ -1147,8 +1147,8 @@ int coroutine_mixed_fn qio_channel_writev_full_all(QIOChannel *ioc,
* If not implemented, acts as a no-op, and returns 0. * If not implemented, acts as a no-op, and returns 0.
* *
* Returns -1 if any error is found, * Returns -1 if any error is found,
* 1 if every send failed to use zero copy. * 1 if at least one send failed to use zero copy.
* 0 otherwise. * 0 if every send successfully used zero copy.
*/ */
int qio_channel_flush(QIOChannel *ioc, int qio_channel_flush(QIOChannel *ioc,

View File

@@ -72,7 +72,7 @@ qio_channel_socket_new(void)
sioc->zero_copy_queued = 0; sioc->zero_copy_queued = 0;
sioc->zero_copy_sent = 0; sioc->zero_copy_sent = 0;
sioc->blocking = false; sioc->blocking = false;
sioc->new_zero_copy_sent_success = false; sioc->zero_copy_fallback = false;
ioc = QIO_CHANNEL(sioc); ioc = QIO_CHANNEL(sioc);
qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN); qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
@@ -880,9 +880,9 @@ static int qio_channel_socket_flush_internal(QIOChannel *ioc,
/* No errors, count successfully finished sendmsg()*/ /* No errors, count successfully finished sendmsg()*/
sioc->zero_copy_sent += serr->ee_data - serr->ee_info + 1; sioc->zero_copy_sent += serr->ee_data - serr->ee_info + 1;
/* If any sendmsg() succeeded using zero copy, mark zerocopy success */ if (serr->ee_code == SO_EE_CODE_ZEROCOPY_COPIED) {
if (serr->ee_code != SO_EE_CODE_ZEROCOPY_COPIED) { /* If any sendmsg() fell back to a copy, mark fallback as true */
sioc->new_zero_copy_sent_success = true; sioc->zero_copy_fallback = true;
} }
} }
@@ -900,12 +900,12 @@ static int qio_channel_socket_flush(QIOChannel *ioc,
return ret; return ret;
} }
if (sioc->new_zero_copy_sent_success) { if (sioc->zero_copy_fallback) {
sioc->new_zero_copy_sent_success = false; sioc->zero_copy_fallback = false;
return 0; return 1;
} }
return 1; return 0;
} }
#endif /* QEMU_MSG_ZEROCOPY */ #endif /* QEMU_MSG_ZEROCOPY */