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. * Helpers for using (partial) iovecs.
* *
* Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
* Copyright (C) 2010 Red Hat, Inc. * Copyright (C) 2010 Red Hat, Inc.
* *
* Author(s): * 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 iov_memset(const struct iovec *iov, const unsigned int iov_cnt,
size_t offset, int fillc, size_t bytes); 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 * Send/recv data from/to iovec buffers directly
* *

View File

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