xref: /spdk/lib/util/iov.c (revision 60982c759db49b4f4579f16e3b24df0725ba4b94)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2019 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/util.h"
7 
8 void
9 spdk_iov_memset(struct iovec *iovs, int iovcnt, int c)
10 {
11 	int iov_idx = 0;
12 	struct iovec *iov;
13 
14 	while (iov_idx < iovcnt) {
15 		iov = &iovs[iov_idx];
16 		memset(iov->iov_base, c, iov->iov_len);
17 		iov_idx++;
18 	}
19 }
20 
21 void
22 spdk_iov_one(struct iovec *iov, int *iovcnt, void *buf, size_t buflen)
23 {
24 	iov->iov_base = buf;
25 	iov->iov_len = buflen;
26 	*iovcnt = 1;
27 }
28 
29 size_t
30 spdk_ioviter_first(struct spdk_ioviter *iter,
31 		   struct iovec *siov, size_t siovcnt,
32 		   struct iovec *diov, size_t diovcnt,
33 		   void **src, void **dst)
34 {
35 	struct iovec *iovs[2];
36 	size_t iovcnts[2];
37 	void *out[2];
38 	size_t len;
39 
40 	iovs[0] = siov;
41 	iovcnts[0] = siovcnt;
42 
43 	iovs[1] = diov;
44 	iovcnts[1] = diovcnt;
45 
46 	len = spdk_ioviter_firstv(iter, 2, iovs, iovcnts, out);
47 
48 	if (len > 0) {
49 		*src = out[0];
50 		*dst = out[1];
51 	}
52 
53 	return len;
54 }
55 
56 size_t
57 spdk_ioviter_firstv(struct spdk_ioviter *iter,
58 		    uint32_t count,
59 		    struct iovec **iov,
60 		    size_t *iovcnt,
61 		    void **out)
62 {
63 	struct spdk_single_ioviter *it;
64 	uint32_t i;
65 
66 	iter->count = count;
67 
68 	for (i = 0; i < count; i++) {
69 		it = &iter->iters[i];
70 		it->iov = iov[i];
71 		it->iovcnt = iovcnt[i];
72 		it->idx = 0;
73 		it->iov_len = iov[i][0].iov_len;
74 		it->iov_base = iov[i][0].iov_base;
75 	}
76 
77 	return spdk_ioviter_nextv(iter, out);
78 }
79 
80 size_t
81 spdk_ioviter_next(struct spdk_ioviter *iter, void **src, void **dst)
82 {
83 	void *out[2];
84 	size_t len;
85 
86 	len = spdk_ioviter_nextv(iter, out);
87 
88 	if (len > 0) {
89 		*src = out[0];
90 		*dst = out[1];
91 	}
92 
93 	return len;
94 }
95 
96 size_t
97 spdk_ioviter_nextv(struct spdk_ioviter *iter, void **out)
98 {
99 	struct spdk_single_ioviter *it;
100 	size_t len;
101 	uint32_t i;
102 
103 	/* Figure out the minimum size of each iovec's next segment */
104 	len = UINT32_MAX;
105 	for (i = 0; i < iter->count; i++) {
106 		it = &iter->iters[i];
107 		if (it->idx == it->iovcnt || it->iov_len == 0) {
108 			/* This element has 0 bytes remaining, so we're done. */
109 			return 0;
110 		}
111 
112 		len = spdk_min(len, it->iov_len);
113 	}
114 
115 	for (i = 0; i < iter->count; i++) {
116 		it = &iter->iters[i];
117 
118 		out[i] = it->iov_base;
119 
120 		if (it->iov_len == len) {
121 			/* Advance to next element */
122 			it->idx++;
123 			if (it->idx != it->iovcnt) {
124 				/* Set up for next element */
125 				it->iov_len = it->iov[it->idx].iov_len;
126 				it->iov_base = it->iov[it->idx].iov_base;
127 			}
128 		} else {
129 			/* Partial buffer */
130 			it->iov_base += len;
131 			it->iov_len -= len;
132 		}
133 	}
134 
135 	return len;
136 }
137 
138 size_t
139 spdk_iovcpy(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_t diovcnt)
140 {
141 	struct spdk_ioviter iter;
142 	size_t len, total_sz;
143 	void *src, *dst;
144 
145 	total_sz = 0;
146 	for (len = spdk_ioviter_first(&iter, siov, siovcnt, diov, diovcnt, &src, &dst);
147 	     len != 0;
148 	     len = spdk_ioviter_next(&iter, &src, &dst)) {
149 		memcpy(dst, src, len);
150 		total_sz += len;
151 	}
152 
153 	return total_sz;
154 }
155 
156 size_t
157 spdk_iovmove(struct iovec *siov, size_t siovcnt, struct iovec *diov, size_t diovcnt)
158 {
159 	struct spdk_ioviter iter;
160 	size_t len, total_sz;
161 	void *src, *dst;
162 
163 	total_sz = 0;
164 	for (len = spdk_ioviter_first(&iter, siov, siovcnt, diov, diovcnt, &src, &dst);
165 	     len != 0;
166 	     len = spdk_ioviter_next(&iter, &src, &dst)) {
167 		memmove(dst, src, len);
168 		total_sz += len;
169 	}
170 
171 	return total_sz;
172 }
173 
174 void
175 spdk_iov_xfer_init(struct spdk_iov_xfer *ix, struct iovec *iovs, int iovcnt)
176 {
177 	ix->iovs = iovs;
178 	ix->iovcnt = iovcnt;
179 	ix->cur_iov_idx = 0;
180 	ix->cur_iov_offset = 0;
181 }
182 
183 static size_t
184 iov_xfer(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len, bool to_buf)
185 {
186 	size_t len, iov_remain_len, copied_len = 0;
187 	struct iovec *iov;
188 
189 	if (buf_len == 0) {
190 		return 0;
191 	}
192 
193 	while (ix->cur_iov_idx < ix->iovcnt) {
194 		iov = &ix->iovs[ix->cur_iov_idx];
195 		iov_remain_len = iov->iov_len - ix->cur_iov_offset;
196 		if (iov_remain_len == 0) {
197 			ix->cur_iov_idx++;
198 			ix->cur_iov_offset = 0;
199 			continue;
200 		}
201 
202 		len = spdk_min(iov_remain_len, buf_len - copied_len);
203 
204 		if (to_buf) {
205 			memcpy((char *)buf + copied_len,
206 			       (char *)iov->iov_base + ix->cur_iov_offset, len);
207 		} else {
208 			memcpy((char *)iov->iov_base + ix->cur_iov_offset,
209 			       (const char *)buf + copied_len, len);
210 		}
211 		copied_len += len;
212 		ix->cur_iov_offset += len;
213 
214 		if (buf_len == copied_len) {
215 			return copied_len;
216 		}
217 	}
218 
219 	return copied_len;
220 }
221 
222 size_t
223 spdk_iov_xfer_from_buf(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len)
224 {
225 	return iov_xfer(ix, buf, buf_len, false);
226 }
227 
228 size_t
229 spdk_iov_xfer_to_buf(struct spdk_iov_xfer *ix, const void *buf, size_t buf_len)
230 {
231 	return iov_xfer(ix, buf, buf_len, true);
232 }
233 
234 void
235 spdk_copy_iovs_to_buf(void *buf, size_t buf_len, struct iovec *iovs, int iovcnt)
236 {
237 	struct spdk_iov_xfer ix;
238 
239 	spdk_iov_xfer_init(&ix, iovs, iovcnt);
240 	spdk_iov_xfer_to_buf(&ix, buf, buf_len);
241 }
242 
243 void
244 spdk_copy_buf_to_iovs(struct iovec *iovs, int iovcnt, void *buf, size_t buf_len)
245 {
246 	struct spdk_iov_xfer ix;
247 
248 	spdk_iov_xfer_init(&ix, iovs, iovcnt);
249 	spdk_iov_xfer_from_buf(&ix, buf, buf_len);
250 }
251