2 * Helpers for getting linearized buffers from iov / filling buffers into iovs
4 * Copyright IBM, Corp. 2007, 2008
5 * Copyright (C) 2010 Red Hat, Inc.
8 * Anthony Liguori <aliguori@us.ibm.com>
9 * Amit Shah <amit.shah@redhat.com>
10 * Michael Tokarev <mjt@tls.msk.ru>
12 * This work is licensed under the terms of the GNU GPL, version 2. See
13 * the COPYING file in the top-level directory.
15 * Contributions after 2012-01-13 are licensed under the terms of the
16 * GNU GPL, version 2 or (at your option) any later version.
19 #include "qemu/osdep.h"
21 #include "qemu/sockets.h"
23 size_t iov_from_buf(const struct iovec
*iov
, unsigned int iov_cnt
,
24 size_t offset
, const void *buf
, size_t bytes
)
28 for (i
= 0, done
= 0; (offset
|| done
< bytes
) && i
< iov_cnt
; i
++) {
29 if (offset
< iov
[i
].iov_len
) {
30 size_t len
= MIN(iov
[i
].iov_len
- offset
, bytes
- done
);
31 memcpy(iov
[i
].iov_base
+ offset
, buf
+ done
, len
);
35 offset
-= iov
[i
].iov_len
;
42 size_t iov_to_buf(const struct iovec
*iov
, const unsigned int iov_cnt
,
43 size_t offset
, void *buf
, size_t bytes
)
47 for (i
= 0, done
= 0; (offset
|| done
< bytes
) && i
< iov_cnt
; i
++) {
48 if (offset
< iov
[i
].iov_len
) {
49 size_t len
= MIN(iov
[i
].iov_len
- offset
, bytes
- done
);
50 memcpy(buf
+ done
, iov
[i
].iov_base
+ offset
, len
);
54 offset
-= iov
[i
].iov_len
;
61 size_t iov_memset(const struct iovec
*iov
, const unsigned int iov_cnt
,
62 size_t offset
, int fillc
, size_t bytes
)
66 for (i
= 0, done
= 0; (offset
|| done
< bytes
) && i
< iov_cnt
; i
++) {
67 if (offset
< iov
[i
].iov_len
) {
68 size_t len
= MIN(iov
[i
].iov_len
- offset
, bytes
- done
);
69 memset(iov
[i
].iov_base
+ offset
, fillc
, len
);
73 offset
-= iov
[i
].iov_len
;
80 size_t iov_size(const struct iovec
*iov
, const unsigned int iov_cnt
)
86 for (i
= 0; i
< iov_cnt
; i
++) {
87 len
+= iov
[i
].iov_len
;
92 /* helper function for iov_send_recv() */
94 do_send_recv(int sockfd
, struct iovec
*iov
, unsigned iov_cnt
, bool do_send
)
99 memset(&msg
, 0, sizeof(msg
));
101 msg
.msg_iovlen
= iov_cnt
;
104 ? sendmsg(sockfd
, &msg
, 0)
105 : recvmsg(sockfd
, &msg
, 0);
106 } while (ret
< 0 && errno
== EINTR
);
109 /* else send piece-by-piece */
110 /*XXX Note: windows has WSASend() and WSARecv() */
113 while (i
< iov_cnt
) {
115 ? send(sockfd
, iov
[i
].iov_base
, iov
[i
].iov_len
, 0)
116 : recv(sockfd
, iov
[i
].iov_base
, iov
[i
].iov_len
, 0);
121 } else if (errno
== EINTR
) {
124 /* else it is some "other" error,
125 * only return if there was no data processed. */
137 ssize_t
iov_send_recv(int sockfd
, const struct iovec
*_iov
, unsigned iov_cnt
,
138 size_t offset
, size_t bytes
,
143 size_t orig_len
, tail
;
145 struct iovec
*local_iov
, *iov
;
151 local_iov
= g_new0(struct iovec
, iov_cnt
);
152 iov_copy(local_iov
, iov_cnt
, _iov
, iov_cnt
, offset
, bytes
);
157 /* Find the start position, skipping `offset' bytes:
158 * first, skip all full-sized vector elements, */
159 for (niov
= 0; niov
< iov_cnt
&& offset
>= iov
[niov
].iov_len
; ++niov
) {
160 offset
-= iov
[niov
].iov_len
;
163 /* niov == iov_cnt would only be valid if bytes == 0, which
164 * we already ruled out in the loop condition. */
165 assert(niov
< iov_cnt
);
170 /* second, skip `offset' bytes from the (now) first element,
172 iov
[0].iov_base
+= offset
;
173 iov
[0].iov_len
-= offset
;
175 /* Find the end position skipping `bytes' bytes: */
176 /* first, skip all full-sized elements */
178 for (niov
= 0; niov
< iov_cnt
&& iov
[niov
].iov_len
<= tail
; ++niov
) {
179 tail
-= iov
[niov
].iov_len
;
182 /* second, fixup the last element, and remember the original
184 assert(niov
< iov_cnt
);
185 assert(iov
[niov
].iov_len
> tail
);
186 orig_len
= iov
[niov
].iov_len
;
187 iov
[niov
++].iov_len
= tail
;
188 ret
= do_send_recv(sockfd
, iov
, niov
, do_send
);
189 /* Undo the changes above before checking for errors */
190 iov
[niov
-1].iov_len
= orig_len
;
192 ret
= do_send_recv(sockfd
, iov
, niov
, do_send
);
195 iov
[0].iov_base
-= offset
;
196 iov
[0].iov_len
+= offset
;
200 assert(errno
!= EINTR
);
202 if (errno
== EAGAIN
&& total
> 0) {
208 if (ret
== 0 && !do_send
) {
209 /* recv returns 0 when the peer has performed an orderly
214 /* Prepare for the next iteration */
225 void iov_hexdump(const struct iovec
*iov
, const unsigned int iov_cnt
,
226 FILE *fp
, const char *prefix
, size_t limit
)
232 for (v
= 0; v
< iov_cnt
; v
++) {
233 size
+= iov
[v
].iov_len
;
235 size
= size
> limit
? limit
: size
;
236 buf
= g_malloc(size
);
237 iov_to_buf(iov
, iov_cnt
, 0, buf
, size
);
238 qemu_hexdump(buf
, fp
, prefix
, size
);
242 unsigned iov_copy(struct iovec
*dst_iov
, unsigned int dst_iov_cnt
,
243 const struct iovec
*iov
, unsigned int iov_cnt
,
244 size_t offset
, size_t bytes
)
248 for (i
= 0, j
= 0; i
< iov_cnt
&& j
< dst_iov_cnt
&& bytes
; i
++) {
249 if (offset
>= iov
[i
].iov_len
) {
250 offset
-= iov
[i
].iov_len
;
253 len
= MIN(bytes
, iov
[i
].iov_len
- offset
);
255 dst_iov
[j
].iov_base
= iov
[i
].iov_base
+ offset
;
256 dst_iov
[j
].iov_len
= len
;
267 void qemu_iovec_init(QEMUIOVector
*qiov
, int alloc_hint
)
269 qiov
->iov
= g_new(struct iovec
, alloc_hint
);
271 qiov
->nalloc
= alloc_hint
;
275 void qemu_iovec_init_external(QEMUIOVector
*qiov
, struct iovec
*iov
, int niov
)
283 for (i
= 0; i
< niov
; i
++)
284 qiov
->size
+= iov
[i
].iov_len
;
287 void qemu_iovec_add(QEMUIOVector
*qiov
, void *base
, size_t len
)
289 assert(qiov
->nalloc
!= -1);
291 if (qiov
->niov
== qiov
->nalloc
) {
292 qiov
->nalloc
= 2 * qiov
->nalloc
+ 1;
293 qiov
->iov
= g_renew(struct iovec
, qiov
->iov
, qiov
->nalloc
);
295 qiov
->iov
[qiov
->niov
].iov_base
= base
;
296 qiov
->iov
[qiov
->niov
].iov_len
= len
;
302 * Concatenates (partial) iovecs from src_iov to the end of dst.
303 * It starts copying after skipping `soffset' bytes at the
304 * beginning of src and adds individual vectors from src to
305 * dst copies up to `sbytes' bytes total, or up to the end
306 * of src_iov if it comes first. This way, it is okay to specify
307 * very large value for `sbytes' to indicate "up to the end
309 * Only vector pointers are processed, not the actual data buffers.
311 size_t qemu_iovec_concat_iov(QEMUIOVector
*dst
,
312 struct iovec
*src_iov
, unsigned int src_cnt
,
313 size_t soffset
, size_t sbytes
)
321 assert(dst
->nalloc
!= -1);
322 for (i
= 0, done
= 0; done
< sbytes
&& i
< src_cnt
; i
++) {
323 if (soffset
< src_iov
[i
].iov_len
) {
324 size_t len
= MIN(src_iov
[i
].iov_len
- soffset
, sbytes
- done
);
325 qemu_iovec_add(dst
, src_iov
[i
].iov_base
+ soffset
, len
);
329 soffset
-= src_iov
[i
].iov_len
;
332 assert(soffset
== 0); /* offset beyond end of src */
338 * Concatenates (partial) iovecs from src to the end of dst.
339 * It starts copying after skipping `soffset' bytes at the
340 * beginning of src and adds individual vectors from src to
341 * dst copies up to `sbytes' bytes total, or up to the end
342 * of src if it comes first. This way, it is okay to specify
343 * very large value for `sbytes' to indicate "up to the end
345 * Only vector pointers are processed, not the actual data buffers.
347 void qemu_iovec_concat(QEMUIOVector
*dst
,
348 QEMUIOVector
*src
, size_t soffset
, size_t sbytes
)
350 qemu_iovec_concat_iov(dst
, src
->iov
, src
->niov
, soffset
, sbytes
);
354 * Check if the contents of the iovecs are all zero
356 bool qemu_iovec_is_zero(QEMUIOVector
*qiov
)
359 for (i
= 0; i
< qiov
->niov
; i
++) {
360 size_t offs
= QEMU_ALIGN_DOWN(qiov
->iov
[i
].iov_len
, 4 * sizeof(long));
361 uint8_t *ptr
= qiov
->iov
[i
].iov_base
;
362 if (offs
&& !buffer_is_zero(qiov
->iov
[i
].iov_base
, offs
)) {
365 for (; offs
< qiov
->iov
[i
].iov_len
; offs
++) {
374 void qemu_iovec_destroy(QEMUIOVector
*qiov
)
376 assert(qiov
->nalloc
!= -1);
378 qemu_iovec_reset(qiov
);
384 void qemu_iovec_reset(QEMUIOVector
*qiov
)
386 assert(qiov
->nalloc
!= -1);
392 size_t qemu_iovec_to_buf(QEMUIOVector
*qiov
, size_t offset
,
393 void *buf
, size_t bytes
)
395 return iov_to_buf(qiov
->iov
, qiov
->niov
, offset
, buf
, bytes
);
398 size_t qemu_iovec_from_buf(QEMUIOVector
*qiov
, size_t offset
,
399 const void *buf
, size_t bytes
)
401 return iov_from_buf(qiov
->iov
, qiov
->niov
, offset
, buf
, bytes
);
404 size_t qemu_iovec_memset(QEMUIOVector
*qiov
, size_t offset
,
405 int fillc
, size_t bytes
)
407 return iov_memset(qiov
->iov
, qiov
->niov
, offset
, fillc
, bytes
);
411 * Check that I/O vector contents are identical
413 * The IO vectors must have the same structure (same length of all parts).
414 * A typical usage is to compare vectors created with qemu_iovec_clone().
418 * @ret: Offset to first mismatching byte or -1 if match
420 ssize_t
qemu_iovec_compare(QEMUIOVector
*a
, QEMUIOVector
*b
)
425 assert(a
->niov
== b
->niov
);
426 for (i
= 0; i
< a
->niov
; i
++) {
428 uint8_t *p
= (uint8_t *)a
->iov
[i
].iov_base
;
429 uint8_t *q
= (uint8_t *)b
->iov
[i
].iov_base
;
431 assert(a
->iov
[i
].iov_len
== b
->iov
[i
].iov_len
);
432 while (len
< a
->iov
[i
].iov_len
&& *p
++ == *q
++) {
438 if (len
!= a
->iov
[i
].iov_len
) {
447 struct iovec
*src_iov
;
451 static int sortelem_cmp_src_base(const void *a
, const void *b
)
453 const IOVectorSortElem
*elem_a
= a
;
454 const IOVectorSortElem
*elem_b
= b
;
457 if (elem_a
->src_iov
->iov_base
< elem_b
->src_iov
->iov_base
) {
459 } else if (elem_a
->src_iov
->iov_base
> elem_b
->src_iov
->iov_base
) {
466 static int sortelem_cmp_src_index(const void *a
, const void *b
)
468 const IOVectorSortElem
*elem_a
= a
;
469 const IOVectorSortElem
*elem_b
= b
;
471 return elem_a
->src_index
- elem_b
->src_index
;
475 * Copy contents of I/O vector
477 * The relative relationships of overlapping iovecs are preserved. This is
478 * necessary to ensure identical semantics in the cloned I/O vector.
480 void qemu_iovec_clone(QEMUIOVector
*dest
, const QEMUIOVector
*src
, void *buf
)
482 IOVectorSortElem sortelems
[src
->niov
];
486 /* Sort by source iovecs by base address */
487 for (i
= 0; i
< src
->niov
; i
++) {
488 sortelems
[i
].src_index
= i
;
489 sortelems
[i
].src_iov
= &src
->iov
[i
];
491 qsort(sortelems
, src
->niov
, sizeof(sortelems
[0]), sortelem_cmp_src_base
);
493 /* Allocate buffer space taking into account overlapping iovecs */
495 for (i
= 0; i
< src
->niov
; i
++) {
496 struct iovec
*cur
= sortelems
[i
].src_iov
;
497 ptrdiff_t rewind
= 0;
500 if (last_end
&& last_end
> cur
->iov_base
) {
501 rewind
= last_end
- cur
->iov_base
;
504 sortelems
[i
].dest_base
= buf
- rewind
;
505 buf
+= cur
->iov_len
- MIN(rewind
, cur
->iov_len
);
506 last_end
= MAX(cur
->iov_base
+ cur
->iov_len
, last_end
);
509 /* Sort by source iovec index and build destination iovec */
510 qsort(sortelems
, src
->niov
, sizeof(sortelems
[0]), sortelem_cmp_src_index
);
511 for (i
= 0; i
< src
->niov
; i
++) {
512 qemu_iovec_add(dest
, sortelems
[i
].dest_base
, src
->iov
[i
].iov_len
);
516 size_t iov_discard_front(struct iovec
**iov
, unsigned int *iov_cnt
,
522 for (cur
= *iov
; *iov_cnt
> 0; cur
++) {
523 if (cur
->iov_len
> bytes
) {
524 cur
->iov_base
+= bytes
;
525 cur
->iov_len
-= bytes
;
530 bytes
-= cur
->iov_len
;
531 total
+= cur
->iov_len
;
539 size_t iov_discard_back(struct iovec
*iov
, unsigned int *iov_cnt
,
549 cur
= iov
+ (*iov_cnt
- 1);
551 while (*iov_cnt
> 0) {
552 if (cur
->iov_len
> bytes
) {
553 cur
->iov_len
-= bytes
;
558 bytes
-= cur
->iov_len
;
559 total
+= cur
->iov_len
;
567 void qemu_iovec_discard_back(QEMUIOVector
*qiov
, size_t bytes
)
570 unsigned int niov
= qiov
->niov
;
572 assert(qiov
->size
>= bytes
);
573 total
= iov_discard_back(qiov
->iov
, &niov
, bytes
);
574 assert(total
== bytes
);