On Tue, Feb 06, 2024 at 03:28:10PM +0100, Laurent Vivier wrote:On 2/5/24 06:57, David Gibson wrote:Right, but done starts at 0 and will remain zero until you reach the first segment where you need to copy something. So, unless bytes == 0, then done < bytes will always be true when offset != 0. And if bytes *is* zero, then there's nothing to do, so there's no need to step through the vector at all.On Fri, Feb 02, 2024 at 03:11:28PM +0100, Laurent Vivier wrote: ...In fact the loop has two purposes: 1- scan the the iovec to reach byte offset in the iov (so until offset is 0) 2- copy the bytes (until done == byte) It could be written like this: for (i = 0; offset && i < iov_cnt && offset >= iov[i].iov_len ; i++) offset -= iov[i].iov_len; for (done = 0; done < bytes && i < iov_cnt; i++) { size_t len = MIN(iov[i].iov_len - offset, bytes - done); memcpy((char *)iov[i].iov_base + offset, (char *)buf + done, len); done += len; }diff --git a/iov.c b/iov.c new file mode 100644 index 000000000000..38a8e7566021 --- /dev/null +++ b/iov.c + for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {Not immediately seeing why you need the 'offset ||' part of the condition....Ok, fair enough.In fact this function will be removed with "vhost-user: use guest buffer directly in vu_handle_tx()" as it is not needed when we use directly guest buffers. So I don't think we need to improve this.+unsigned iov_copy(struct iovec *dst_iov, unsigned int dst_iov_cnt, + const struct iovec *iov, unsigned int iov_cnt, + size_t offset, size_t bytes) +{ + size_t len; + unsigned int i, j; + for (i = 0, j = 0; + i < iov_cnt && j < dst_iov_cnt && (offset || bytes); i++) { + if (offset >= iov[i].iov_len) { + offset -= iov[i].iov_len; + continue; + } + len = MIN(bytes, iov[i].iov_len - offset); + + dst_iov[j].iov_base = (char *)iov[i].iov_base + offset; + dst_iov[j].iov_len = len; + j++; + bytes -= len; + offset = 0; + } + return j; +}Small concern about the interface to iov_copy(). If dst_iov_cnt < iov_cnt and the chunk of the input iovec you want doesn't fit in the destination it will silently truncate - you can't tell if this has happened from the return value. If the assumption is that dst_iov_cnt = iov_cnt, then there's not really any need to pass it.If I remember correctly I think it behaves like passt already does with socket backend: if it doesn't fit, it's dropped silently. I've fixed all your other comments. Thanks, Laurent-- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson