io: add qio_channel_readv_full_all_eof & qio_channel_readv_full_all helpers

Adds qio_channel_readv_full_all_eof() and qio_channel_readv_full_all()
to read both data and FDs. Refactors existing code to use these helpers.

Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com>
Signed-off-by: John G Johnson <john.g.johnson@oracle.com>
Signed-off-by: Jagannathan Raman <jag.raman@oracle.com>
Acked-by: Daniel P. Berrangé <berrange@redhat.com>
Message-id: b059c4cc0fb741e794d644c144cc21372cad877d.1611938319.git.jag.raman@oracle.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
stable-6.0
Elena Ufimtseva 2021-01-29 11:46:09 -05:00 committed by Stefan Hajnoczi
parent bfa4238750
commit bebab91ebd
2 changed files with 134 additions and 20 deletions

View File

@ -777,6 +777,59 @@ void qio_channel_set_aio_fd_handler(QIOChannel *ioc,
IOHandler *io_write,
void *opaque);
/**
* qio_channel_readv_full_all_eof:
* @ioc: the channel object
* @iov: the array of memory regions to read data to
* @niov: the length of the @iov array
* @fds: an array of file handles to read
* @nfds: number of file handles in @fds
* @errp: pointer to a NULL-initialized error object
*
*
* Performs same function as qio_channel_readv_all_eof.
* Additionally, attempts to read file descriptors shared
* over the channel. The function will wait for all
* requested data to be read, yielding from the current
* coroutine if required. data refers to both file
* descriptors and the iovs.
*
* Returns: 1 if all bytes were read, 0 if end-of-file
* occurs without data, or -1 on error
*/
int qio_channel_readv_full_all_eof(QIOChannel *ioc,
const struct iovec *iov,
size_t niov,
int **fds, size_t *nfds,
Error **errp);
/**
* qio_channel_readv_full_all:
* @ioc: the channel object
* @iov: the array of memory regions to read data to
* @niov: the length of the @iov array
* @fds: an array of file handles to read
* @nfds: number of file handles in @fds
* @errp: pointer to a NULL-initialized error object
*
*
* Performs same function as qio_channel_readv_all_eof.
* Additionally, attempts to read file descriptors shared
* over the channel. The function will wait for all
* requested data to be read, yielding from the current
* coroutine if required. data refers to both file
* descriptors and the iovs.
*
* Returns: 0 if all bytes were read, or -1 on error
*/
int qio_channel_readv_full_all(QIOChannel *ioc,
const struct iovec *iov,
size_t niov,
int **fds, size_t *nfds,
Error **errp);
/**
* qio_channel_writev_full_all:
* @ioc: the channel object

View File

@ -91,20 +91,48 @@ int qio_channel_readv_all_eof(QIOChannel *ioc,
const struct iovec *iov,
size_t niov,
Error **errp)
{
return qio_channel_readv_full_all_eof(ioc, iov, niov, NULL, NULL, errp);
}
int qio_channel_readv_all(QIOChannel *ioc,
const struct iovec *iov,
size_t niov,
Error **errp)
{
return qio_channel_readv_full_all(ioc, iov, niov, NULL, NULL, errp);
}
int qio_channel_readv_full_all_eof(QIOChannel *ioc,
const struct iovec *iov,
size_t niov,
int **fds, size_t *nfds,
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;
int **local_fds = fds;
size_t *local_nfds = nfds;
bool partial = false;
if (nfds) {
*nfds = 0;
}
if (fds) {
*fds = NULL;
}
nlocal_iov = iov_copy(local_iov, nlocal_iov,
iov, niov,
0, iov_size(iov, niov));
while (nlocal_iov > 0) {
while ((nlocal_iov > 0) || local_fds) {
ssize_t len;
len = qio_channel_readv(ioc, local_iov, nlocal_iov, errp);
len = qio_channel_readv_full(ioc, local_iov, nlocal_iov, local_fds,
local_nfds, errp);
if (len == QIO_CHANNEL_ERR_BLOCK) {
if (qemu_in_coroutine()) {
qio_channel_yield(ioc, G_IO_IN);
@ -112,20 +140,50 @@ int qio_channel_readv_all_eof(QIOChannel *ioc,
qio_channel_wait(ioc, G_IO_IN);
}
continue;
} else if (len < 0) {
goto cleanup;
} else if (len == 0) {
if (partial) {
error_setg(errp,
"Unexpected end-of-file before all bytes were read");
} else {
}
if (len == 0) {
if (local_nfds && *local_nfds) {
/*
* Got some FDs, but no data yet. This isn't an EOF
* scenario (yet), so carry on to try to read data
* on next loop iteration
*/
goto next_iter;
} else if (!partial) {
/* No fds and no data - EOF before any data read */
ret = 0;
goto cleanup;
} else {
len = -1;
error_setg(errp,
"Unexpected end-of-file before all data were read");
/* Fallthrough into len < 0 handling */
}
}
if (len < 0) {
/* Close any FDs we previously received */
if (nfds && fds) {
size_t i;
for (i = 0; i < (*nfds); i++) {
close((*fds)[i]);
}
g_free(*fds);
*fds = NULL;
*nfds = 0;
}
goto cleanup;
}
if (nlocal_iov) {
iov_discard_front(&local_iov, &nlocal_iov, len);
}
next_iter:
partial = true;
iov_discard_front(&local_iov, &nlocal_iov, len);
local_fds = NULL;
local_nfds = NULL;
}
ret = 1;
@ -135,20 +193,23 @@ int qio_channel_readv_all_eof(QIOChannel *ioc,
return ret;
}
int qio_channel_readv_all(QIOChannel *ioc,
const struct iovec *iov,
size_t niov,
Error **errp)
int qio_channel_readv_full_all(QIOChannel *ioc,
const struct iovec *iov,
size_t niov,
int **fds, size_t *nfds,
Error **errp)
{
int ret = qio_channel_readv_all_eof(ioc, iov, niov, errp);
int ret = qio_channel_readv_full_all_eof(ioc, iov, niov, fds, nfds, errp);
if (ret == 0) {
ret = -1;
error_setg(errp,
"Unexpected end-of-file before all bytes were read");
} else if (ret == 1) {
ret = 0;
error_prepend(errp,
"Unexpected end-of-file before all data were read.");
return -1;
}
if (ret == 1) {
return 0;
}
return ret;
}