xref: /openbmc/qemu/include/qemu/iov.h (revision cc63f6f6)
11de7afc9SPaolo Bonzini /*
21de7afc9SPaolo Bonzini  * Helpers for using (partial) iovecs.
31de7afc9SPaolo Bonzini  *
41de7afc9SPaolo Bonzini  * Copyright (C) 2010 Red Hat, Inc.
51de7afc9SPaolo Bonzini  *
61de7afc9SPaolo Bonzini  * Author(s):
71de7afc9SPaolo Bonzini  *  Amit Shah <amit.shah@redhat.com>
81de7afc9SPaolo Bonzini  *  Michael Tokarev <mjt@tls.msk.ru>
91de7afc9SPaolo Bonzini  *
101de7afc9SPaolo Bonzini  * This work is licensed under the terms of the GNU GPL, version 2.  See
111de7afc9SPaolo Bonzini  * the COPYING file in the top-level directory.
121de7afc9SPaolo Bonzini  */
131de7afc9SPaolo Bonzini 
141de7afc9SPaolo Bonzini #ifndef IOV_H
151de7afc9SPaolo Bonzini #define IOV_H
161de7afc9SPaolo Bonzini 
171de7afc9SPaolo Bonzini /**
181de7afc9SPaolo Bonzini  * count and return data size, in bytes, of an iovec
191de7afc9SPaolo Bonzini  * starting at `iov' of `iov_cnt' number of elements.
201de7afc9SPaolo Bonzini  */
211de7afc9SPaolo Bonzini size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt);
221de7afc9SPaolo Bonzini 
231de7afc9SPaolo Bonzini /**
241de7afc9SPaolo Bonzini  * Copy from single continuous buffer to scatter-gather vector of buffers
251de7afc9SPaolo Bonzini  * (iovec) and back like memcpy() between two continuous memory regions.
261de7afc9SPaolo Bonzini  * Data in single continuous buffer starting at address `buf' and
271de7afc9SPaolo Bonzini  * `bytes' bytes long will be copied to/from an iovec `iov' with
281de7afc9SPaolo Bonzini  * `iov_cnt' number of elements, starting at byte position `offset'
291de7afc9SPaolo Bonzini  * within the iovec.  If the iovec does not contain enough space,
301de7afc9SPaolo Bonzini  * only part of data will be copied, up to the end of the iovec.
311de7afc9SPaolo Bonzini  * Number of bytes actually copied will be returned, which is
321de7afc9SPaolo Bonzini  *  min(bytes, iov_size(iov)-offset)
331de7afc9SPaolo Bonzini  * `Offset' must point to the inside of iovec.
341de7afc9SPaolo Bonzini  */
35ad523bcaSPaolo Bonzini size_t iov_from_buf_full(const struct iovec *iov, unsigned int iov_cnt,
361de7afc9SPaolo Bonzini                          size_t offset, const void *buf, size_t bytes);
37ad523bcaSPaolo Bonzini size_t iov_to_buf_full(const struct iovec *iov, const unsigned int iov_cnt,
381de7afc9SPaolo Bonzini                        size_t offset, void *buf, size_t bytes);
391de7afc9SPaolo Bonzini 
40ad523bcaSPaolo Bonzini static inline size_t
iov_from_buf(const struct iovec * iov,unsigned int iov_cnt,size_t offset,const void * buf,size_t bytes)41ad523bcaSPaolo Bonzini iov_from_buf(const struct iovec *iov, unsigned int iov_cnt,
42ad523bcaSPaolo Bonzini              size_t offset, const void *buf, size_t bytes)
43ad523bcaSPaolo Bonzini {
44ad523bcaSPaolo Bonzini     if (__builtin_constant_p(bytes) && iov_cnt &&
45ad523bcaSPaolo Bonzini         offset <= iov[0].iov_len && bytes <= iov[0].iov_len - offset) {
46ad523bcaSPaolo Bonzini         memcpy(iov[0].iov_base + offset, buf, bytes);
47ad523bcaSPaolo Bonzini         return bytes;
48ad523bcaSPaolo Bonzini     } else {
49ad523bcaSPaolo Bonzini         return iov_from_buf_full(iov, iov_cnt, offset, buf, bytes);
50ad523bcaSPaolo Bonzini     }
51ad523bcaSPaolo Bonzini }
52ad523bcaSPaolo Bonzini 
53ad523bcaSPaolo Bonzini static inline size_t
iov_to_buf(const struct iovec * iov,const unsigned int iov_cnt,size_t offset,void * buf,size_t bytes)54ad523bcaSPaolo Bonzini iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
55ad523bcaSPaolo Bonzini            size_t offset, void *buf, size_t bytes)
56ad523bcaSPaolo Bonzini {
57ad523bcaSPaolo Bonzini     if (__builtin_constant_p(bytes) && iov_cnt &&
58ad523bcaSPaolo Bonzini         offset <= iov[0].iov_len && bytes <= iov[0].iov_len - offset) {
59ad523bcaSPaolo Bonzini         memcpy(buf, iov[0].iov_base + offset, bytes);
60ad523bcaSPaolo Bonzini         return bytes;
61ad523bcaSPaolo Bonzini     } else {
62ad523bcaSPaolo Bonzini         return iov_to_buf_full(iov, iov_cnt, offset, buf, bytes);
63ad523bcaSPaolo Bonzini     }
64ad523bcaSPaolo Bonzini }
65ad523bcaSPaolo Bonzini 
661de7afc9SPaolo Bonzini /**
671de7afc9SPaolo Bonzini  * Set data bytes pointed out by iovec `iov' of size `iov_cnt' elements,
681de7afc9SPaolo Bonzini  * starting at byte offset `start', to value `fillc', repeating it
691de7afc9SPaolo Bonzini  * `bytes' number of times.  `Offset' must point to the inside of iovec.
701de7afc9SPaolo Bonzini  * If `bytes' is large enough, only last bytes portion of iovec,
711de7afc9SPaolo Bonzini  * up to the end of it, will be filled with the specified value.
721de7afc9SPaolo Bonzini  * Function return actual number of bytes processed, which is
731de7afc9SPaolo Bonzini  * min(size, iov_size(iov) - offset).
741de7afc9SPaolo Bonzini  */
751de7afc9SPaolo Bonzini size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt,
761de7afc9SPaolo Bonzini                   size_t offset, int fillc, size_t bytes);
771de7afc9SPaolo Bonzini 
781de7afc9SPaolo Bonzini /*
791de7afc9SPaolo Bonzini  * Send/recv data from/to iovec buffers directly
801de7afc9SPaolo Bonzini  *
811de7afc9SPaolo Bonzini  * `offset' bytes in the beginning of iovec buffer are skipped and
821de7afc9SPaolo Bonzini  * next `bytes' bytes are used, which must be within data of iovec.
831de7afc9SPaolo Bonzini  *
841de7afc9SPaolo Bonzini  *   r = iov_send_recv(sockfd, iov, iovcnt, offset, bytes, true);
851de7afc9SPaolo Bonzini  *
861de7afc9SPaolo Bonzini  * is logically equivalent to
871de7afc9SPaolo Bonzini  *
881de7afc9SPaolo Bonzini  *   char *buf = malloc(bytes);
891de7afc9SPaolo Bonzini  *   iov_to_buf(iov, iovcnt, offset, buf, bytes);
901de7afc9SPaolo Bonzini  *   r = send(sockfd, buf, bytes, 0);
911de7afc9SPaolo Bonzini  *   free(buf);
921de7afc9SPaolo Bonzini  *
931de7afc9SPaolo Bonzini  * For iov_send_recv() _whole_ area being sent or received
941de7afc9SPaolo Bonzini  * should be within the iovec, not only beginning of it.
951de7afc9SPaolo Bonzini  */
966b64640dSWen Congyang ssize_t iov_send_recv(int sockfd, const struct iovec *iov, unsigned iov_cnt,
971de7afc9SPaolo Bonzini                       size_t offset, size_t bytes, bool do_send);
981de7afc9SPaolo Bonzini #define iov_recv(sockfd, iov, iov_cnt, offset, bytes) \
991de7afc9SPaolo Bonzini   iov_send_recv(sockfd, iov, iov_cnt, offset, bytes, false)
1001de7afc9SPaolo Bonzini #define iov_send(sockfd, iov, iov_cnt, offset, bytes) \
1011de7afc9SPaolo Bonzini   iov_send_recv(sockfd, iov, iov_cnt, offset, bytes, true)
1021de7afc9SPaolo Bonzini 
1031de7afc9SPaolo Bonzini /**
1041de7afc9SPaolo Bonzini  * Produce a text hexdump of iovec `iov' with `iov_cnt' number of elements
1051de7afc9SPaolo Bonzini  * in file `fp', prefixing each line with `prefix' and processing not more
1061de7afc9SPaolo Bonzini  * than `limit' data bytes.
1071de7afc9SPaolo Bonzini  */
1081de7afc9SPaolo Bonzini void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt,
1091de7afc9SPaolo Bonzini                  FILE *fp, const char *prefix, size_t limit);
1101de7afc9SPaolo Bonzini 
1111de7afc9SPaolo Bonzini /*
1121de7afc9SPaolo Bonzini  * Partial copy of vector from iov to dst_iov (data is not copied).
1131de7afc9SPaolo Bonzini  * dst_iov overlaps iov at a specified offset.
1141de7afc9SPaolo Bonzini  * size of dst_iov is at most bytes. dst vector count is returned.
1151de7afc9SPaolo Bonzini  */
1161de7afc9SPaolo Bonzini unsigned iov_copy(struct iovec *dst_iov, unsigned int dst_iov_cnt,
1171de7afc9SPaolo Bonzini                  const struct iovec *iov, unsigned int iov_cnt,
1181de7afc9SPaolo Bonzini                  size_t offset, size_t bytes);
1191de7afc9SPaolo Bonzini 
120d0277635SStefan Hajnoczi /*
121d0277635SStefan Hajnoczi  * Remove a given number of bytes from the front or back of a vector.
122d0277635SStefan Hajnoczi  * This may update iov and/or iov_cnt to exclude iovec elements that are
123d0277635SStefan Hajnoczi  * no longer required.
124d0277635SStefan Hajnoczi  *
125d0277635SStefan Hajnoczi  * The number of bytes actually discarded is returned.  This number may be
126d0277635SStefan Hajnoczi  * smaller than requested if the vector is too small.
127d0277635SStefan Hajnoczi  */
128d0277635SStefan Hajnoczi size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt,
129d0277635SStefan Hajnoczi                          size_t bytes);
130d0277635SStefan Hajnoczi size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt,
131d0277635SStefan Hajnoczi                         size_t bytes);
132d0277635SStefan Hajnoczi 
1339dd6f7c2SStefan Hajnoczi /* Information needed to undo an iov_discard_*() operation */
1349dd6f7c2SStefan Hajnoczi typedef struct {
1359dd6f7c2SStefan Hajnoczi     struct iovec *modified_iov;
1369dd6f7c2SStefan Hajnoczi     struct iovec orig;
1379dd6f7c2SStefan Hajnoczi } IOVDiscardUndo;
1389dd6f7c2SStefan Hajnoczi 
1399dd6f7c2SStefan Hajnoczi /*
1409dd6f7c2SStefan Hajnoczi  * Undo an iov_discard_front_undoable() or iov_discard_back_undoable()
1419dd6f7c2SStefan Hajnoczi  * operation. If multiple operations are made then each one needs a separate
1429dd6f7c2SStefan Hajnoczi  * IOVDiscardUndo and iov_discard_undo() must be called in the reverse order
1439dd6f7c2SStefan Hajnoczi  * that the operations were made.
1449dd6f7c2SStefan Hajnoczi  */
1459dd6f7c2SStefan Hajnoczi void iov_discard_undo(IOVDiscardUndo *undo);
1469dd6f7c2SStefan Hajnoczi 
1479dd6f7c2SStefan Hajnoczi /*
1489dd6f7c2SStefan Hajnoczi  * Undoable versions of iov_discard_front() and iov_discard_back(). Use
1499dd6f7c2SStefan Hajnoczi  * iov_discard_undo() to reset to the state before the discard operations.
1509dd6f7c2SStefan Hajnoczi  */
1519dd6f7c2SStefan Hajnoczi size_t iov_discard_front_undoable(struct iovec **iov, unsigned int *iov_cnt,
1529dd6f7c2SStefan Hajnoczi                                   size_t bytes, IOVDiscardUndo *undo);
1539dd6f7c2SStefan Hajnoczi size_t iov_discard_back_undoable(struct iovec *iov, unsigned int *iov_cnt,
1549dd6f7c2SStefan Hajnoczi                                  size_t bytes, IOVDiscardUndo *undo);
1559dd6f7c2SStefan Hajnoczi 
156daf015efSMarkus Armbruster typedef struct QEMUIOVector {
157daf015efSMarkus Armbruster     struct iovec *iov;
158daf015efSMarkus Armbruster     int niov;
159a1ca3ed5SVladimir Sementsov-Ogievskiy 
160a1ca3ed5SVladimir Sementsov-Ogievskiy     /*
161a1ca3ed5SVladimir Sementsov-Ogievskiy      * For external @iov (qemu_iovec_init_external()) or allocated @iov
162a1ca3ed5SVladimir Sementsov-Ogievskiy      * (qemu_iovec_init()), @size is the cumulative size of iovecs and
163a1ca3ed5SVladimir Sementsov-Ogievskiy      * @local_iov is invalid and unused.
164a1ca3ed5SVladimir Sementsov-Ogievskiy      *
165a1ca3ed5SVladimir Sementsov-Ogievskiy      * For embedded @iov (QEMU_IOVEC_INIT_BUF() or qemu_iovec_init_buf()),
166a1ca3ed5SVladimir Sementsov-Ogievskiy      * @iov is equal to &@local_iov, and @size is valid, as it has same
167a1ca3ed5SVladimir Sementsov-Ogievskiy      * offset and type as @local_iov.iov_len, which is guaranteed by
168a1ca3ed5SVladimir Sementsov-Ogievskiy      * static assertion below.
169a1ca3ed5SVladimir Sementsov-Ogievskiy      *
170a1ca3ed5SVladimir Sementsov-Ogievskiy      * @nalloc is always valid and is -1 both for embedded and external
171a1ca3ed5SVladimir Sementsov-Ogievskiy      * cases. It is included in the union only to ensure the padding prior
172a1ca3ed5SVladimir Sementsov-Ogievskiy      * to the @size field will not result in a 0-length array.
173a1ca3ed5SVladimir Sementsov-Ogievskiy      */
174a1ca3ed5SVladimir Sementsov-Ogievskiy     union {
175a1ca3ed5SVladimir Sementsov-Ogievskiy         struct {
176daf015efSMarkus Armbruster             int nalloc;
177a1ca3ed5SVladimir Sementsov-Ogievskiy             struct iovec local_iov;
178a1ca3ed5SVladimir Sementsov-Ogievskiy         };
179a1ca3ed5SVladimir Sementsov-Ogievskiy         struct {
180a1ca3ed5SVladimir Sementsov-Ogievskiy             char __pad[sizeof(int) + offsetof(struct iovec, iov_len)];
181daf015efSMarkus Armbruster             size_t size;
182a1ca3ed5SVladimir Sementsov-Ogievskiy         };
183a1ca3ed5SVladimir Sementsov-Ogievskiy     };
184daf015efSMarkus Armbruster } QEMUIOVector;
185daf015efSMarkus Armbruster 
186a1ca3ed5SVladimir Sementsov-Ogievskiy QEMU_BUILD_BUG_ON(offsetof(QEMUIOVector, size) !=
187a1ca3ed5SVladimir Sementsov-Ogievskiy                   offsetof(QEMUIOVector, local_iov.iov_len));
188a1ca3ed5SVladimir Sementsov-Ogievskiy 
189a1ca3ed5SVladimir Sementsov-Ogievskiy #define QEMU_IOVEC_INIT_BUF(self, buf, len)              \
190a1ca3ed5SVladimir Sementsov-Ogievskiy {                                                        \
191a1ca3ed5SVladimir Sementsov-Ogievskiy     .iov = &(self).local_iov,                            \
192a1ca3ed5SVladimir Sementsov-Ogievskiy     .niov = 1,                                           \
193a1ca3ed5SVladimir Sementsov-Ogievskiy     .nalloc = -1,                                        \
194a1ca3ed5SVladimir Sementsov-Ogievskiy     .local_iov = {                                       \
195a1ca3ed5SVladimir Sementsov-Ogievskiy         .iov_base = (void *)(buf), /* cast away const */ \
196a1ca3ed5SVladimir Sementsov-Ogievskiy         .iov_len = (len),                                \
197a1ca3ed5SVladimir Sementsov-Ogievskiy     },                                                   \
198a1ca3ed5SVladimir Sementsov-Ogievskiy }
199a1ca3ed5SVladimir Sementsov-Ogievskiy 
200a1ca3ed5SVladimir Sementsov-Ogievskiy /*
201a1ca3ed5SVladimir Sementsov-Ogievskiy  * qemu_iovec_init_buf
202a1ca3ed5SVladimir Sementsov-Ogievskiy  *
203a1ca3ed5SVladimir Sementsov-Ogievskiy  * Initialize embedded QEMUIOVector.
204a1ca3ed5SVladimir Sementsov-Ogievskiy  *
205a1ca3ed5SVladimir Sementsov-Ogievskiy  * Note: "const" is used over @buf pointer to make it simple to pass
206a1ca3ed5SVladimir Sementsov-Ogievskiy  * const pointers, appearing in read functions. Then this "const" is
207a1ca3ed5SVladimir Sementsov-Ogievskiy  * cast away by QEMU_IOVEC_INIT_BUF().
208a1ca3ed5SVladimir Sementsov-Ogievskiy  */
qemu_iovec_init_buf(QEMUIOVector * qiov,const void * buf,size_t len)209a1ca3ed5SVladimir Sementsov-Ogievskiy static inline void qemu_iovec_init_buf(QEMUIOVector *qiov,
210a1ca3ed5SVladimir Sementsov-Ogievskiy                                        const void *buf, size_t len)
211a1ca3ed5SVladimir Sementsov-Ogievskiy {
212a1ca3ed5SVladimir Sementsov-Ogievskiy     *qiov = (QEMUIOVector) QEMU_IOVEC_INIT_BUF(*qiov, buf, len);
213a1ca3ed5SVladimir Sementsov-Ogievskiy }
214a1ca3ed5SVladimir Sementsov-Ogievskiy 
qemu_iovec_buf(QEMUIOVector * qiov)215a1ca3ed5SVladimir Sementsov-Ogievskiy static inline void *qemu_iovec_buf(QEMUIOVector *qiov)
216a1ca3ed5SVladimir Sementsov-Ogievskiy {
217a1ca3ed5SVladimir Sementsov-Ogievskiy     /* Only supports embedded iov */
218a1ca3ed5SVladimir Sementsov-Ogievskiy     assert(qiov->nalloc == -1 && qiov->iov == &qiov->local_iov);
219a1ca3ed5SVladimir Sementsov-Ogievskiy 
220a1ca3ed5SVladimir Sementsov-Ogievskiy     return qiov->local_iov.iov_base;
221a1ca3ed5SVladimir Sementsov-Ogievskiy }
222a1ca3ed5SVladimir Sementsov-Ogievskiy 
223daf015efSMarkus Armbruster void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint);
224daf015efSMarkus Armbruster void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov);
225d953169dSVladimir Sementsov-Ogievskiy void qemu_iovec_init_slice(QEMUIOVector *qiov, QEMUIOVector *source,
226d953169dSVladimir Sementsov-Ogievskiy                            size_t offset, size_t len);
227*3d06cea8SHanna Czenczek struct iovec *qemu_iovec_slice(QEMUIOVector *qiov,
228*3d06cea8SHanna Czenczek                                size_t offset, size_t len,
229*3d06cea8SHanna Czenczek                                size_t *head, size_t *tail, int *niov);
2305396234bSVladimir Sementsov-Ogievskiy int qemu_iovec_subvec_niov(QEMUIOVector *qiov, size_t offset, size_t len);
231daf015efSMarkus Armbruster void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len);
232daf015efSMarkus Armbruster void qemu_iovec_concat(QEMUIOVector *dst,
233daf015efSMarkus Armbruster                        QEMUIOVector *src, size_t soffset, size_t sbytes);
234daf015efSMarkus Armbruster size_t qemu_iovec_concat_iov(QEMUIOVector *dst,
235daf015efSMarkus Armbruster                              struct iovec *src_iov, unsigned int src_cnt,
236daf015efSMarkus Armbruster                              size_t soffset, size_t sbytes);
237f76889e7SVladimir Sementsov-Ogievskiy bool qemu_iovec_is_zero(QEMUIOVector *qiov, size_t qiov_offeset, size_t bytes);
238daf015efSMarkus Armbruster void qemu_iovec_destroy(QEMUIOVector *qiov);
239daf015efSMarkus Armbruster void qemu_iovec_reset(QEMUIOVector *qiov);
240daf015efSMarkus Armbruster size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset,
241daf015efSMarkus Armbruster                          void *buf, size_t bytes);
242daf015efSMarkus Armbruster size_t qemu_iovec_from_buf(QEMUIOVector *qiov, size_t offset,
243daf015efSMarkus Armbruster                            const void *buf, size_t bytes);
244daf015efSMarkus Armbruster size_t qemu_iovec_memset(QEMUIOVector *qiov, size_t offset,
245daf015efSMarkus Armbruster                          int fillc, size_t bytes);
246daf015efSMarkus Armbruster ssize_t qemu_iovec_compare(QEMUIOVector *a, QEMUIOVector *b);
247daf015efSMarkus Armbruster void qemu_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src, void *buf);
248daf015efSMarkus Armbruster void qemu_iovec_discard_back(QEMUIOVector *qiov, size_t bytes);
249daf015efSMarkus Armbruster 
2501de7afc9SPaolo Bonzini #endif
251