util/iov: Introduce iov_send_recv_with_flags()

In order to support a new update function, a flag needs to be passed
to the kernel via the socket send call (MSG_MORE) to notify it that
more data is to be expected to calculate the hash correctly.

Add a new iov helper for this purpose.

Signed-off-by: Alejandro Zeise <alejandro.zeise@seagate.com>
[ clg: - Split iov changes from original patch
       - Checkpatch fixes ]
Signed-off-by: Cédric Le Goater <clg@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Alejandro Zeise 2024-10-08 09:57:13 +02:00 committed by Daniel P. Berrangé
parent 278d596015
commit 78a5822820
2 changed files with 45 additions and 7 deletions

View File

@ -1,6 +1,7 @@
/*
* Helpers for using (partial) iovecs.
*
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (C) 2010 Red Hat, Inc.
*
* Author(s):
@ -75,6 +76,32 @@ iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt,
size_t offset, int fillc, size_t bytes);
/*
* Send/recv data from/to iovec buffers directly, with the provided
* socket flags.
*
* `offset' bytes in the beginning of iovec buffer are skipped and
* next `bytes' bytes are used, which must be within data of iovec.
*
* r = iov_send_recv_with_flags(sockfd, sockflags, iov, iovcnt,
* offset, bytes, true);
*
* is logically equivalent to
*
* char *buf = malloc(bytes);
* iov_to_buf(iov, iovcnt, offset, buf, bytes);
* r = send(sockfd, buf, bytes, sockflags);
* free(buf);
*
* For iov_send_recv_with_flags() _whole_ area being sent or received
* should be within the iovec, not only beginning of it.
*/
ssize_t iov_send_recv_with_flags(int sockfd, int sockflags,
const struct iovec *iov,
unsigned iov_cnt, size_t offset,
size_t bytes,
bool do_send);
/*
* Send/recv data from/to iovec buffers directly
*

View File

@ -3,6 +3,7 @@
*
* Copyright IBM, Corp. 2007, 2008
* Copyright (C) 2010 Red Hat, Inc.
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
*
* Author(s):
* Anthony Liguori <aliguori@us.ibm.com>
@ -92,7 +93,8 @@ size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt)
/* helper function for iov_send_recv() */
static ssize_t
do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
do_send_recv(int sockfd, int flags, struct iovec *iov, unsigned iov_cnt,
bool do_send)
{
#ifdef CONFIG_POSIX
ssize_t ret;
@ -102,8 +104,8 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
msg.msg_iovlen = iov_cnt;
do {
ret = do_send
? sendmsg(sockfd, &msg, 0)
: recvmsg(sockfd, &msg, 0);
? sendmsg(sockfd, &msg, flags)
: recvmsg(sockfd, &msg, flags);
} while (ret < 0 && errno == EINTR);
return ret;
#else
@ -114,8 +116,8 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
ssize_t off = 0;
while (i < iov_cnt) {
ssize_t r = do_send
? send(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, 0)
: recv(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, 0);
? send(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, flags)
: recv(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, flags);
if (r > 0) {
ret += r;
off += r;
@ -144,6 +146,15 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
ssize_t iov_send_recv(int sockfd, const struct iovec *_iov, unsigned iov_cnt,
size_t offset, size_t bytes,
bool do_send)
{
return iov_send_recv_with_flags(sockfd, 0, _iov, iov_cnt, offset, bytes,
do_send);
}
ssize_t iov_send_recv_with_flags(int sockfd, int sockflags,
const struct iovec *_iov,
unsigned iov_cnt, size_t offset,
size_t bytes, bool do_send)
{
ssize_t total = 0;
ssize_t ret;
@ -192,11 +203,11 @@ ssize_t iov_send_recv(int sockfd, const struct iovec *_iov, unsigned iov_cnt,
assert(iov[niov].iov_len > tail);
orig_len = iov[niov].iov_len;
iov[niov++].iov_len = tail;
ret = do_send_recv(sockfd, iov, niov, do_send);
ret = do_send_recv(sockfd, sockflags, iov, niov, do_send);
/* Undo the changes above before checking for errors */
iov[niov-1].iov_len = orig_len;
} else {
ret = do_send_recv(sockfd, iov, niov, do_send);
ret = do_send_recv(sockfd, sockflags, iov, niov, do_send);
}
if (offset) {
iov[0].iov_base -= offset;