1 | /* |
2 | * Helpers for using (partial) iovecs. |
3 | * |
4 | * Copyright (C) 2010 Red Hat, Inc. |
5 | * |
6 | * Author(s): |
7 | * Amit Shah <amit.shah@redhat.com> |
8 | * Michael Tokarev <mjt@tls.msk.ru> |
9 | * |
10 | * This work is licensed under the terms of the GNU GPL, version 2. See |
11 | * the COPYING file in the top-level directory. |
12 | */ |
13 | |
14 | #ifndef IOV_H |
15 | #define IOV_H |
16 | |
17 | /** |
18 | * count and return data size, in bytes, of an iovec |
19 | * starting at `iov' of `iov_cnt' number of elements. |
20 | */ |
21 | size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt); |
22 | |
23 | /** |
24 | * Copy from single continuous buffer to scatter-gather vector of buffers |
25 | * (iovec) and back like memcpy() between two continuous memory regions. |
26 | * Data in single continuous buffer starting at address `buf' and |
27 | * `bytes' bytes long will be copied to/from an iovec `iov' with |
28 | * `iov_cnt' number of elements, starting at byte position `offset' |
29 | * within the iovec. If the iovec does not contain enough space, |
30 | * only part of data will be copied, up to the end of the iovec. |
31 | * Number of bytes actually copied will be returned, which is |
32 | * min(bytes, iov_size(iov)-offset) |
33 | * `Offset' must point to the inside of iovec. |
34 | */ |
35 | size_t iov_from_buf_full(const struct iovec *iov, unsigned int iov_cnt, |
36 | size_t offset, const void *buf, size_t bytes); |
37 | size_t iov_to_buf_full(const struct iovec *iov, const unsigned int iov_cnt, |
38 | size_t offset, void *buf, size_t bytes); |
39 | |
40 | static inline size_t |
41 | iov_from_buf(const struct iovec *iov, unsigned int iov_cnt, |
42 | size_t offset, const void *buf, size_t bytes) |
43 | { |
44 | if (__builtin_constant_p(bytes) && iov_cnt && |
45 | offset <= iov[0].iov_len && bytes <= iov[0].iov_len - offset) { |
46 | memcpy(iov[0].iov_base + offset, buf, bytes); |
47 | return bytes; |
48 | } else { |
49 | return iov_from_buf_full(iov, iov_cnt, offset, buf, bytes); |
50 | } |
51 | } |
52 | |
53 | static inline size_t |
54 | iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt, |
55 | size_t offset, void *buf, size_t bytes) |
56 | { |
57 | if (__builtin_constant_p(bytes) && iov_cnt && |
58 | offset <= iov[0].iov_len && bytes <= iov[0].iov_len - offset) { |
59 | memcpy(buf, iov[0].iov_base + offset, bytes); |
60 | return bytes; |
61 | } else { |
62 | return iov_to_buf_full(iov, iov_cnt, offset, buf, bytes); |
63 | } |
64 | } |
65 | |
66 | /** |
67 | * Set data bytes pointed out by iovec `iov' of size `iov_cnt' elements, |
68 | * starting at byte offset `start', to value `fillc', repeating it |
69 | * `bytes' number of times. `Offset' must point to the inside of iovec. |
70 | * If `bytes' is large enough, only last bytes portion of iovec, |
71 | * up to the end of it, will be filled with the specified value. |
72 | * Function return actual number of bytes processed, which is |
73 | * min(size, iov_size(iov) - offset). |
74 | */ |
75 | size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt, |
76 | size_t offset, int fillc, size_t bytes); |
77 | |
78 | /* |
79 | * Send/recv data from/to iovec buffers directly |
80 | * |
81 | * `offset' bytes in the beginning of iovec buffer are skipped and |
82 | * next `bytes' bytes are used, which must be within data of iovec. |
83 | * |
84 | * r = iov_send_recv(sockfd, iov, iovcnt, offset, bytes, true); |
85 | * |
86 | * is logically equivalent to |
87 | * |
88 | * char *buf = malloc(bytes); |
89 | * iov_to_buf(iov, iovcnt, offset, buf, bytes); |
90 | * r = send(sockfd, buf, bytes, 0); |
91 | * free(buf); |
92 | * |
93 | * For iov_send_recv() _whole_ area being sent or received |
94 | * should be within the iovec, not only beginning of it. |
95 | */ |
96 | ssize_t iov_send_recv(int sockfd, const struct iovec *iov, unsigned iov_cnt, |
97 | size_t offset, size_t bytes, bool do_send); |
98 | #define iov_recv(sockfd, iov, iov_cnt, offset, bytes) \ |
99 | iov_send_recv(sockfd, iov, iov_cnt, offset, bytes, false) |
100 | #define iov_send(sockfd, iov, iov_cnt, offset, bytes) \ |
101 | iov_send_recv(sockfd, iov, iov_cnt, offset, bytes, true) |
102 | |
103 | /** |
104 | * Produce a text hexdump of iovec `iov' with `iov_cnt' number of elements |
105 | * in file `fp', prefixing each line with `prefix' and processing not more |
106 | * than `limit' data bytes. |
107 | */ |
108 | void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt, |
109 | FILE *fp, const char *prefix, size_t limit); |
110 | |
111 | /* |
112 | * Partial copy of vector from iov to dst_iov (data is not copied). |
113 | * dst_iov overlaps iov at a specified offset. |
114 | * size of dst_iov is at most bytes. dst vector count is returned. |
115 | */ |
116 | unsigned iov_copy(struct iovec *dst_iov, unsigned int dst_iov_cnt, |
117 | const struct iovec *iov, unsigned int iov_cnt, |
118 | size_t offset, size_t bytes); |
119 | |
120 | /* |
121 | * Remove a given number of bytes from the front or back of a vector. |
122 | * This may update iov and/or iov_cnt to exclude iovec elements that are |
123 | * no longer required. |
124 | * |
125 | * The number of bytes actually discarded is returned. This number may be |
126 | * smaller than requested if the vector is too small. |
127 | */ |
128 | size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt, |
129 | size_t bytes); |
130 | size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt, |
131 | size_t bytes); |
132 | |
133 | typedef struct QEMUIOVector { |
134 | struct iovec *iov; |
135 | int niov; |
136 | |
137 | /* |
138 | * For external @iov (qemu_iovec_init_external()) or allocated @iov |
139 | * (qemu_iovec_init()), @size is the cumulative size of iovecs and |
140 | * @local_iov is invalid and unused. |
141 | * |
142 | * For embedded @iov (QEMU_IOVEC_INIT_BUF() or qemu_iovec_init_buf()), |
143 | * @iov is equal to &@local_iov, and @size is valid, as it has same |
144 | * offset and type as @local_iov.iov_len, which is guaranteed by |
145 | * static assertion below. |
146 | * |
147 | * @nalloc is always valid and is -1 both for embedded and external |
148 | * cases. It is included in the union only to ensure the padding prior |
149 | * to the @size field will not result in a 0-length array. |
150 | */ |
151 | union { |
152 | struct { |
153 | int nalloc; |
154 | struct iovec local_iov; |
155 | }; |
156 | struct { |
157 | char __pad[sizeof(int) + offsetof(struct iovec, iov_len)]; |
158 | size_t size; |
159 | }; |
160 | }; |
161 | } QEMUIOVector; |
162 | |
163 | QEMU_BUILD_BUG_ON(offsetof(QEMUIOVector, size) != |
164 | offsetof(QEMUIOVector, local_iov.iov_len)); |
165 | |
166 | #define QEMU_IOVEC_INIT_BUF(self, buf, len) \ |
167 | { \ |
168 | .iov = &(self).local_iov, \ |
169 | .niov = 1, \ |
170 | .nalloc = -1, \ |
171 | .local_iov = { \ |
172 | .iov_base = (void *)(buf), /* cast away const */ \ |
173 | .iov_len = (len), \ |
174 | }, \ |
175 | } |
176 | |
177 | /* |
178 | * qemu_iovec_init_buf |
179 | * |
180 | * Initialize embedded QEMUIOVector. |
181 | * |
182 | * Note: "const" is used over @buf pointer to make it simple to pass |
183 | * const pointers, appearing in read functions. Then this "const" is |
184 | * cast away by QEMU_IOVEC_INIT_BUF(). |
185 | */ |
186 | static inline void qemu_iovec_init_buf(QEMUIOVector *qiov, |
187 | const void *buf, size_t len) |
188 | { |
189 | *qiov = (QEMUIOVector) QEMU_IOVEC_INIT_BUF(*qiov, buf, len); |
190 | } |
191 | |
192 | static inline void *qemu_iovec_buf(QEMUIOVector *qiov) |
193 | { |
194 | /* Only supports embedded iov */ |
195 | assert(qiov->nalloc == -1 && qiov->iov == &qiov->local_iov); |
196 | |
197 | return qiov->local_iov.iov_base; |
198 | } |
199 | |
200 | void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint); |
201 | void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov); |
202 | void qemu_iovec_init_extended( |
203 | QEMUIOVector *qiov, |
204 | void *head_buf, size_t head_len, |
205 | QEMUIOVector *mid_qiov, size_t mid_offset, size_t mid_len, |
206 | void *tail_buf, size_t tail_len); |
207 | void qemu_iovec_init_slice(QEMUIOVector *qiov, QEMUIOVector *source, |
208 | size_t offset, size_t len); |
209 | int qemu_iovec_subvec_niov(QEMUIOVector *qiov, size_t offset, size_t len); |
210 | void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len); |
211 | void qemu_iovec_concat(QEMUIOVector *dst, |
212 | QEMUIOVector *src, size_t soffset, size_t sbytes); |
213 | size_t qemu_iovec_concat_iov(QEMUIOVector *dst, |
214 | struct iovec *src_iov, unsigned int src_cnt, |
215 | size_t soffset, size_t sbytes); |
216 | bool qemu_iovec_is_zero(QEMUIOVector *qiov, size_t qiov_offeset, size_t bytes); |
217 | void qemu_iovec_destroy(QEMUIOVector *qiov); |
218 | void qemu_iovec_reset(QEMUIOVector *qiov); |
219 | size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset, |
220 | void *buf, size_t bytes); |
221 | size_t qemu_iovec_from_buf(QEMUIOVector *qiov, size_t offset, |
222 | const void *buf, size_t bytes); |
223 | size_t qemu_iovec_memset(QEMUIOVector *qiov, size_t offset, |
224 | int fillc, size_t bytes); |
225 | ssize_t qemu_iovec_compare(QEMUIOVector *a, QEMUIOVector *b); |
226 | void qemu_iovec_clone(QEMUIOVector *dest, const QEMUIOVector *src, void *buf); |
227 | void qemu_iovec_discard_back(QEMUIOVector *qiov, size_t bytes); |
228 | |
229 | #endif |
230 | |