mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
tools/libxs: Use writev()/sendmsg() instead of write()
With the input data now conveniently arranged, use writev()/sendmsg() instead
of decomposing it into write() calls.
This causes all requests to be submitted with a single system call, rather
than at least two. While in principle short writes can occur, the chances of
it happening are slim given that most xenbus comms are only a handful of
bytes.
Nevertheless, provide {writev,sendmsg}_exact() wrappers which take care of
resubmitting on EINTR or short write.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Jason Andryuk <jason.andryuk@amd.com>
master commit: ebaeb0c64a
master date: 2024-07-23 15:11:27 +0100
This commit is contained in:
1 parent
f30071fbb0
commit
28934a0748
1 file changed
+85
-3
+85
-3
@@ -572,6 +572,89 @@ static void *read_reply(
|
||||
return body;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update an iov/nr pair after an incomplete writev()/sendmsg().
|
||||
*
|
||||
* Awkwardly, nr has different widths and signs between writev() and
|
||||
* sendmsg(), so we take it and return it by value, rather than by pointer.
|
||||
*/
|
||||
static size_t update_iov(struct iovec **p_iov, size_t nr, size_t res)
|
||||
{
|
||||
struct iovec *iov = *p_iov;
|
||||
|
||||
/* Skip fully complete elements, including empty elements. */
|
||||
while (nr && res >= iov->iov_len) {
|
||||
res -= iov->iov_len;
|
||||
nr--;
|
||||
iov++;
|
||||
}
|
||||
|
||||
/* Partial element, adjust base/len. */
|
||||
if (res) {
|
||||
iov->iov_len -= res;
|
||||
iov->iov_base += res;
|
||||
}
|
||||
|
||||
*p_iov = iov;
|
||||
|
||||
return nr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper around sendmsg() to resubmit on EINTR or short write. Returns
|
||||
* @true if all data was transmitted, or @false with errno for an error.
|
||||
* Note: May alter @iov in place on resubmit.
|
||||
*/
|
||||
static bool sendmsg_exact(int fd, struct iovec *iov, unsigned int nr)
|
||||
{
|
||||
struct msghdr hdr = {
|
||||
.msg_iov = iov,
|
||||
.msg_iovlen = nr,
|
||||
};
|
||||
|
||||
while (hdr.msg_iovlen) {
|
||||
ssize_t res = sendmsg(fd, &hdr, 0);
|
||||
|
||||
if (res < 0 && errno == EINTR)
|
||||
continue;
|
||||
if (res <= 0)
|
||||
return false;
|
||||
|
||||
hdr.msg_iovlen = update_iov(&hdr.msg_iov, hdr.msg_iovlen, res);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper around sendmsg() to resubmit on EINTR or short write. Returns
|
||||
* @true if all data was transmitted, or @false with errno for an error.
|
||||
* Note: May alter @iov in place on resubmit.
|
||||
*/
|
||||
static bool writev_exact(int fd, struct iovec *iov, unsigned int nr)
|
||||
{
|
||||
while (nr) {
|
||||
ssize_t res = writev(fd, iov, nr);
|
||||
|
||||
if (res < 0 && errno == EINTR)
|
||||
continue;
|
||||
if (res <= 0)
|
||||
return false;
|
||||
|
||||
nr = update_iov(&iov, nr, res);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_request(struct xs_handle *h, struct iovec *iov, unsigned int nr)
|
||||
{
|
||||
if (h->is_socket)
|
||||
return sendmsg_exact(h->fd, iov, nr);
|
||||
else
|
||||
return writev_exact(h->fd, iov, nr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send message to xenstore, get malloc'ed reply. NULL and set errno on error.
|
||||
*
|
||||
@@ -614,9 +697,8 @@ static void *xs_talkv(struct xs_handle *h,
|
||||
|
||||
mutex_lock(&h->request_mutex);
|
||||
|
||||
for (i = 0; i < num_vecs; i++)
|
||||
if (!xs_write_all(h->fd, iovec[i].iov_base, iovec[i].iov_len))
|
||||
goto fail;
|
||||
if (!write_request(h, iovec, num_vecs))
|
||||
goto fail;
|
||||
|
||||
ret = read_reply(h, &reply_type, len);
|
||||
if (!ret)
|
||||
|
||||