Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2023 Intel Corporation. All rights reserved.
3 : : */
4 : :
5 : : #include "spdk_internal/cunit.h"
6 : :
7 : : #include "common/lib/ut_multithread.c"
8 : : #include "unit/lib/json_mock.c"
9 : :
10 : : #include "spdk/config.h"
11 : : #include "spdk/thread.h"
12 : :
13 : : #include "thread/iobuf.c"
14 : :
15 : : struct ut_iobuf_entry {
16 : : struct spdk_iobuf_channel *ioch;
17 : : struct spdk_iobuf_entry iobuf;
18 : : void *buf;
19 : : uint32_t thread_id;
20 : : const char *module;
21 : : };
22 : :
23 : : static void
24 : 12 : ut_iobuf_finish_cb(void *ctx)
25 : : {
26 [ + - ]: 12 : *(int *)ctx = 1;
27 : 12 : }
28 : :
29 : : static void
30 : 72 : ut_iobuf_get_buf_cb(struct spdk_iobuf_entry *entry, void *buf)
31 : : {
32 : 72 : struct ut_iobuf_entry *ut_entry = SPDK_CONTAINEROF(entry, struct ut_iobuf_entry, iobuf);
33 : :
34 [ + - + - ]: 72 : ut_entry->buf = buf;
35 : 72 : }
36 : :
37 : : static int
38 : 48 : ut_iobuf_foreach_cb(struct spdk_iobuf_channel *ch, struct spdk_iobuf_entry *entry, void *cb_arg)
39 : : {
40 : 48 : struct ut_iobuf_entry *ut_entry = SPDK_CONTAINEROF(entry, struct ut_iobuf_entry, iobuf);
41 : :
42 [ + - + - ]: 48 : ut_entry->buf = cb_arg;
43 : :
44 : 48 : return 0;
45 : 8 : }
46 : :
47 : : #define SMALL_BUFSIZE 4096
48 : : #define LARGE_BUFSIZE 8192
49 : :
50 : : static void
51 : 6 : iobuf(void)
52 : : {
53 : 6 : struct spdk_iobuf_opts opts = {
54 : : .small_pool_count = 2,
55 : : .large_pool_count = 2,
56 : : .small_bufsize = SMALL_BUFSIZE,
57 : : .large_bufsize = LARGE_BUFSIZE,
58 : : };
59 : 1 : struct ut_iobuf_entry *entry;
60 : 5 : struct spdk_iobuf_channel mod0_ch[2], mod1_ch[2];
61 : 6 : struct ut_iobuf_entry mod0_entries[] = {
62 : : { .thread_id = 0, .module = "ut_module0", },
63 : : { .thread_id = 0, .module = "ut_module0", },
64 : : { .thread_id = 0, .module = "ut_module0", },
65 : : { .thread_id = 0, .module = "ut_module0", },
66 : : { .thread_id = 1, .module = "ut_module0", },
67 : : { .thread_id = 1, .module = "ut_module0", },
68 : : { .thread_id = 1, .module = "ut_module0", },
69 : : { .thread_id = 1, .module = "ut_module0", },
70 : : };
71 : 6 : struct ut_iobuf_entry mod1_entries[] = {
72 : : { .thread_id = 0, .module = "ut_module1", },
73 : : { .thread_id = 0, .module = "ut_module1", },
74 : : { .thread_id = 0, .module = "ut_module1", },
75 : : { .thread_id = 0, .module = "ut_module1", },
76 : : { .thread_id = 1, .module = "ut_module1", },
77 : : { .thread_id = 1, .module = "ut_module1", },
78 : : { .thread_id = 1, .module = "ut_module1", },
79 : : { .thread_id = 1, .module = "ut_module1", },
80 : : };
81 : 6 : int rc, finish = 0;
82 : 1 : uint32_t i;
83 : :
84 : 6 : allocate_cores(2);
85 : 6 : allocate_threads(2);
86 : :
87 : 6 : set_thread(0);
88 : :
89 : : /* We cannot use spdk_iobuf_set_opts(), as it won't allow us to use such small pools */
90 : 6 : g_iobuf.opts = opts;
91 : 6 : rc = spdk_iobuf_initialize();
92 : 6 : CU_ASSERT_EQUAL(rc, 0);
93 : :
94 : 6 : rc = spdk_iobuf_register_module("ut_module0");
95 : 6 : CU_ASSERT_EQUAL(rc, 0);
96 : :
97 : 6 : rc = spdk_iobuf_register_module("ut_module1");
98 : 6 : CU_ASSERT_EQUAL(rc, 0);
99 : :
100 : 6 : set_thread(0);
101 [ + - + - ]: 6 : rc = spdk_iobuf_channel_init(&mod0_ch[0], "ut_module0", 0, 0);
102 : 6 : CU_ASSERT_EQUAL(rc, 0);
103 : 6 : set_thread(1);
104 [ + - + - ]: 6 : rc = spdk_iobuf_channel_init(&mod0_ch[1], "ut_module0", 0, 0);
105 : 6 : CU_ASSERT_EQUAL(rc, 0);
106 [ + + ]: 54 : for (i = 0; i < SPDK_COUNTOF(mod0_entries); ++i) {
107 [ + - + - : 48 : mod0_entries[i].ioch = &mod0_ch[mod0_entries[i].thread_id];
+ - + - +
- + - + -
+ - + - +
- ]
108 : 8 : }
109 : 6 : set_thread(0);
110 [ + - + - ]: 6 : rc = spdk_iobuf_channel_init(&mod1_ch[0], "ut_module1", 0, 0);
111 : 6 : CU_ASSERT_EQUAL(rc, 0);
112 : 6 : set_thread(1);
113 [ + - + - ]: 6 : rc = spdk_iobuf_channel_init(&mod1_ch[1], "ut_module1", 0, 0);
114 : 6 : CU_ASSERT_EQUAL(rc, 0);
115 [ + + ]: 54 : for (i = 0; i < SPDK_COUNTOF(mod1_entries); ++i) {
116 [ + - + - : 48 : mod1_entries[i].ioch = &mod1_ch[mod1_entries[i].thread_id];
+ - + - +
- + - + -
+ - + - +
- ]
117 : 8 : }
118 : :
119 : : /* First check that it's possible to retrieve the whole pools from a single module */
120 : 6 : set_thread(0);
121 [ + - + - ]: 6 : entry = &mod0_entries[0];
122 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
123 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
124 [ + - + - ]: 6 : entry = &mod0_entries[1];
125 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
126 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
127 : : /* The next two should be put onto the large buf wait queue */
128 [ + - + - ]: 6 : entry = &mod0_entries[2];
129 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
130 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
131 [ + - + - ]: 6 : entry = &mod0_entries[3];
132 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
133 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
134 : : /* Pick the two next buffers from the small pool */
135 : 6 : set_thread(1);
136 [ + - + - ]: 6 : entry = &mod0_entries[4];
137 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
138 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
139 [ + - + - ]: 6 : entry = &mod0_entries[5];
140 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
141 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
142 : : /* The next two should be put onto the small buf wait queue */
143 [ + - + - ]: 6 : entry = &mod0_entries[6];
144 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
145 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
146 [ + - + - ]: 6 : entry = &mod0_entries[7];
147 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
148 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
149 : :
150 : : /* Now return one of the large buffers to the pool and verify that the first request's
151 : : * (entry 2) callback was executed and it was removed from the wait queue.
152 : : */
153 : 6 : set_thread(0);
154 [ + - + - ]: 6 : entry = &mod0_entries[0];
155 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
+ - + - ]
156 [ + - + - ]: 6 : entry = &mod0_entries[2];
157 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
158 [ + - + - ]: 6 : entry = &mod0_entries[3];
159 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
160 : :
161 : : /* Return the second buffer and check that the other request is satisfied */
162 [ + - + - ]: 6 : entry = &mod0_entries[1];
163 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
+ - + - ]
164 [ + - + - ]: 6 : entry = &mod0_entries[3];
165 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
166 : :
167 : : /* Return the remaining two buffers */
168 [ + - + - ]: 6 : entry = &mod0_entries[2];
169 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
+ - + - ]
170 [ + - + - ]: 6 : entry = &mod0_entries[3];
171 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
+ - + - ]
172 : :
173 : : /* Check that it didn't change the requests waiting for the small buffers */
174 [ + - + - ]: 6 : entry = &mod0_entries[6];
175 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
176 [ + - + - ]: 6 : entry = &mod0_entries[7];
177 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
178 : :
179 : : /* Do the same test as above, this time using the small pool */
180 : 6 : set_thread(1);
181 [ + - + - ]: 6 : entry = &mod0_entries[4];
182 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
+ - + - ]
183 [ + - + - ]: 6 : entry = &mod0_entries[6];
184 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
185 [ + - + - ]: 6 : entry = &mod0_entries[7];
186 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
187 : :
188 : : /* Return the second buffer and check that the other request is satisfied */
189 [ + - + - ]: 6 : entry = &mod0_entries[5];
190 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
+ - + - ]
191 [ + - + - ]: 6 : entry = &mod0_entries[7];
192 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
193 : :
194 : : /* Return the remaining two buffers */
195 [ + - + - ]: 6 : entry = &mod0_entries[6];
196 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
+ - + - ]
197 [ + - + - ]: 6 : entry = &mod0_entries[7];
198 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
+ - + - ]
199 : :
200 : : /* Now check requesting buffers from different modules - first request all of them from one
201 : : * module, starting from the large pool
202 : : */
203 : 6 : set_thread(0);
204 [ + - + - ]: 6 : entry = &mod0_entries[0];
205 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
206 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
207 [ + - + - ]: 6 : entry = &mod0_entries[1];
208 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
209 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
210 : : /* Request all of them from the small one */
211 : 6 : set_thread(1);
212 [ + - + - ]: 6 : entry = &mod0_entries[4];
213 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
214 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
215 [ + - + - ]: 6 : entry = &mod0_entries[5];
216 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
217 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
218 : :
219 : : /* Request one buffer per module from each pool */
220 : 6 : set_thread(0);
221 [ + - + - ]: 6 : entry = &mod1_entries[0];
222 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
223 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
224 [ + - + - ]: 6 : entry = &mod0_entries[3];
225 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
226 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
227 : : /* Change the order from the small pool and request a buffer from mod0 first */
228 : 6 : set_thread(1);
229 [ + - + - ]: 6 : entry = &mod0_entries[6];
230 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
231 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
232 [ + - + - ]: 6 : entry = &mod1_entries[4];
233 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
234 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
235 : :
236 : : /* Now return one buffer to the large pool */
237 : 6 : set_thread(0);
238 [ + - + - ]: 6 : entry = &mod0_entries[0];
239 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
+ - + - ]
240 : :
241 : : /* Make sure the request from mod1 got the buffer, as it was the first to request it */
242 [ + - + - ]: 6 : entry = &mod1_entries[0];
243 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
244 [ + - + - ]: 6 : entry = &mod0_entries[3];
245 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
246 : :
247 : : /* Return second buffer to the large pool and check the outstanding mod0 request */
248 [ + - + - ]: 6 : entry = &mod0_entries[1];
249 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
+ - + - ]
250 [ + - + - ]: 6 : entry = &mod0_entries[3];
251 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
252 : :
253 : : /* Return the remaining two buffers */
254 [ + - + - ]: 6 : entry = &mod1_entries[0];
255 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
+ - + - ]
256 [ + - + - ]: 6 : entry = &mod0_entries[3];
257 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
+ - + - ]
258 : :
259 : : /* Check the same for the small pool, but this time the order of the request is reversed
260 : : * (mod0 before mod1)
261 : : */
262 : 6 : set_thread(1);
263 [ + - + - ]: 6 : entry = &mod0_entries[4];
264 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
+ - + - ]
265 [ + - + - ]: 6 : entry = &mod0_entries[6];
266 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
267 : : /* mod1 request was second in this case, so it still needs to wait */
268 [ + - + - ]: 6 : entry = &mod1_entries[4];
269 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
270 : :
271 : : /* Return the second requested buffer */
272 [ + - + - ]: 6 : entry = &mod0_entries[5];
273 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
+ - + - ]
274 [ + - + - ]: 6 : entry = &mod1_entries[4];
275 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
276 : :
277 : : /* Return the remaining two buffers */
278 [ + - + - ]: 6 : entry = &mod0_entries[6];
279 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
+ - + - ]
280 [ + - + - ]: 6 : entry = &mod1_entries[4];
281 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
+ - + - ]
282 : :
283 : : /* Request buffers to make the pools empty */
284 : 6 : set_thread(0);
285 [ + - + - ]: 6 : entry = &mod0_entries[0];
286 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
287 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
288 [ + - + - ]: 6 : entry = &mod1_entries[0];
289 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
290 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
291 [ + - + - ]: 6 : entry = &mod0_entries[1];
292 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
293 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
294 [ + - + - ]: 6 : entry = &mod1_entries[1];
295 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
296 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
297 : :
298 : : /* Queue more requests from both modules */
299 [ + - + - ]: 6 : entry = &mod0_entries[2];
300 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
301 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
302 [ + - + - ]: 6 : entry = &mod1_entries[2];
303 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
304 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
305 [ + - + - ]: 6 : entry = &mod1_entries[3];
306 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
307 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
308 [ + - + - ]: 6 : entry = &mod0_entries[3];
309 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
310 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
311 : :
312 : : /* Check that abort correctly remove an entry from the queue */
313 [ + - + - ]: 6 : entry = &mod0_entries[2];
314 [ + - + - : 6 : spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, LARGE_BUFSIZE);
+ - ]
315 [ + - + - ]: 6 : entry = &mod1_entries[3];
316 [ + - + - : 6 : spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, SMALL_BUFSIZE);
+ - ]
317 : :
318 [ + - + - ]: 6 : entry = &mod0_entries[0];
319 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
+ - + - ]
320 [ + - + - : 6 : CU_ASSERT_PTR_NOT_NULL(mod1_entries[2].buf);
+ - + - ]
321 [ + - + - ]: 6 : entry = &mod0_entries[1];
322 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
+ - + - ]
323 [ + - + - : 6 : CU_ASSERT_PTR_NOT_NULL(mod0_entries[3].buf);
+ - + - ]
324 : :
325 : : /* Clean up */
326 [ + - + - ]: 6 : entry = &mod1_entries[0];
327 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
+ - + - ]
328 [ + - + - ]: 6 : entry = &mod1_entries[2];
329 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
+ - + - ]
330 [ + - + - ]: 6 : entry = &mod1_entries[1];
331 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
+ - + - ]
332 [ + - + - ]: 6 : entry = &mod0_entries[3];
333 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
+ - + - ]
334 : :
335 : : /* Request buffers to make the pools empty */
336 : 6 : set_thread(0);
337 [ + - + - ]: 6 : entry = &mod0_entries[0];
338 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
339 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
340 [ + - + - ]: 6 : entry = &mod1_entries[0];
341 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
342 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
343 [ + - + - ]: 6 : entry = &mod0_entries[1];
344 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
345 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
346 [ + - + - ]: 6 : entry = &mod1_entries[1];
347 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
348 [ + - + - ]: 6 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
349 : :
350 : : /* Request a buffer from each queue and each module on thread 0 */
351 : 6 : set_thread(0);
352 [ + - + - ]: 6 : entry = &mod0_entries[2];
353 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
354 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
355 [ + - + - ]: 6 : entry = &mod1_entries[2];
356 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
357 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
358 [ + - + - ]: 6 : entry = &mod0_entries[3];
359 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
360 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
361 [ + - + - ]: 6 : entry = &mod1_entries[3];
362 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
363 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
364 : :
365 : : /* Do the same on thread 1 */
366 : 6 : set_thread(1);
367 [ + - + - ]: 6 : entry = &mod0_entries[6];
368 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
369 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
370 [ + - + - ]: 6 : entry = &mod1_entries[6];
371 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, LARGE_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
372 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
373 [ + - + - ]: 6 : entry = &mod0_entries[7];
374 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
375 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
376 [ + - + - ]: 6 : entry = &mod1_entries[7];
377 [ + - + - : 6 : entry->buf = spdk_iobuf_get(entry->ioch, SMALL_BUFSIZE, &entry->iobuf, ut_iobuf_get_buf_cb);
+ - + - +
- ]
378 [ + - + - ]: 6 : CU_ASSERT_PTR_NULL(entry->buf);
379 : :
380 : : /* Now do the foreach and check that correct entries are iterated over by assigning their
381 : : * ->buf pointers to different values.
382 : : */
383 : 6 : set_thread(0);
384 [ + - + - : 6 : rc = spdk_iobuf_for_each_entry(&mod0_ch[0], &mod0_ch[0].large,
+ - + - ]
385 : : ut_iobuf_foreach_cb, (void *)0xdeadbeef);
386 : 6 : CU_ASSERT_EQUAL(rc, 0);
387 [ + - + - : 6 : rc = spdk_iobuf_for_each_entry(&mod0_ch[0], &mod0_ch[0].small,
+ - + - ]
388 : : ut_iobuf_foreach_cb, (void *)0xbeefdead);
389 : 6 : CU_ASSERT_EQUAL(rc, 0);
390 [ + - + - : 6 : rc = spdk_iobuf_for_each_entry(&mod1_ch[0], &mod1_ch[0].large,
+ - + - ]
391 : : ut_iobuf_foreach_cb, (void *)0xfeedbeef);
392 : 6 : CU_ASSERT_EQUAL(rc, 0);
393 [ + - + - : 6 : rc = spdk_iobuf_for_each_entry(&mod1_ch[0], &mod1_ch[0].small,
+ - + - ]
394 : : ut_iobuf_foreach_cb, (void *)0xbeeffeed);
395 : 6 : CU_ASSERT_EQUAL(rc, 0);
396 : 6 : set_thread(1);
397 [ + - + - : 6 : rc = spdk_iobuf_for_each_entry(&mod0_ch[1], &mod0_ch[1].large,
+ - + - +
- ]
398 : : ut_iobuf_foreach_cb, (void *)0xcafebabe);
399 : 6 : CU_ASSERT_EQUAL(rc, 0);
400 [ + - + - : 6 : rc = spdk_iobuf_for_each_entry(&mod0_ch[1], &mod0_ch[1].small,
+ - + - +
- ]
401 : : ut_iobuf_foreach_cb, (void *)0xbabecafe);
402 : 6 : CU_ASSERT_EQUAL(rc, 0);
403 [ + - + - : 6 : rc = spdk_iobuf_for_each_entry(&mod1_ch[1], &mod1_ch[1].large,
+ - + - +
- ]
404 : : ut_iobuf_foreach_cb, (void *)0xbeefcafe);
405 : 6 : CU_ASSERT_EQUAL(rc, 0);
406 [ + - + - : 6 : rc = spdk_iobuf_for_each_entry(&mod1_ch[1], &mod1_ch[1].small,
+ - + - +
- ]
407 : : ut_iobuf_foreach_cb, (void *)0xcafebeef);
408 : 6 : CU_ASSERT_EQUAL(rc, 0);
409 : :
410 : : /* thread 0 */
411 [ + - + - : 6 : CU_ASSERT_PTR_EQUAL(mod0_entries[2].buf, (void *)0xdeadbeef);
+ - + - ]
412 [ + - + - : 6 : CU_ASSERT_PTR_EQUAL(mod0_entries[3].buf, (void *)0xbeefdead);
+ - + - ]
413 [ + - + - : 6 : CU_ASSERT_PTR_EQUAL(mod1_entries[2].buf, (void *)0xfeedbeef);
+ - + - ]
414 [ + - + - : 6 : CU_ASSERT_PTR_EQUAL(mod1_entries[3].buf, (void *)0xbeeffeed);
+ - + - ]
415 : : /* thread 1 */
416 [ + - + - : 6 : CU_ASSERT_PTR_EQUAL(mod0_entries[6].buf, (void *)0xcafebabe);
+ - + - ]
417 [ + - + - : 6 : CU_ASSERT_PTR_EQUAL(mod0_entries[7].buf, (void *)0xbabecafe);
+ - + - ]
418 [ + - + - : 6 : CU_ASSERT_PTR_EQUAL(mod1_entries[6].buf, (void *)0xbeefcafe);
+ - + - ]
419 [ + - + - : 6 : CU_ASSERT_PTR_EQUAL(mod1_entries[7].buf, (void *)0xcafebeef);
+ - + - ]
420 : :
421 : : /* Clean everything up */
422 : 6 : set_thread(0);
423 [ + - + - ]: 6 : entry = &mod0_entries[2];
424 [ + - + - : 6 : spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, LARGE_BUFSIZE);
+ - ]
425 [ + - + - ]: 6 : entry = &mod0_entries[3];
426 [ + - + - : 6 : spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, SMALL_BUFSIZE);
+ - ]
427 [ + - + - ]: 6 : entry = &mod1_entries[2];
428 [ + - + - : 6 : spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, LARGE_BUFSIZE);
+ - ]
429 [ + - + - ]: 6 : entry = &mod1_entries[3];
430 [ + - + - : 6 : spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, SMALL_BUFSIZE);
+ - ]
431 : :
432 [ + - + - ]: 6 : entry = &mod0_entries[0];
433 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
+ - + - ]
434 [ + - + - ]: 6 : entry = &mod1_entries[0];
435 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, LARGE_BUFSIZE);
+ - + - ]
436 [ + - + - ]: 6 : entry = &mod0_entries[1];
437 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
+ - + - ]
438 [ + - + - ]: 6 : entry = &mod1_entries[1];
439 [ + - + - : 6 : spdk_iobuf_put(entry->ioch, entry->buf, SMALL_BUFSIZE);
+ - + - ]
440 : :
441 : 6 : set_thread(1);
442 [ + - + - ]: 6 : entry = &mod0_entries[6];
443 [ + - + - : 6 : spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, LARGE_BUFSIZE);
+ - ]
444 [ + - + - ]: 6 : entry = &mod0_entries[7];
445 [ + - + - : 6 : spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, SMALL_BUFSIZE);
+ - ]
446 [ + - + - ]: 6 : entry = &mod1_entries[6];
447 [ + - + - : 6 : spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, LARGE_BUFSIZE);
+ - ]
448 [ + - + - ]: 6 : entry = &mod1_entries[7];
449 [ + - + - : 6 : spdk_iobuf_entry_abort(entry->ioch, &entry->iobuf, SMALL_BUFSIZE);
+ - ]
450 : :
451 : 6 : set_thread(0);
452 [ + - + - ]: 6 : spdk_iobuf_channel_fini(&mod0_ch[0]);
453 : 6 : poll_threads();
454 [ + - + - ]: 6 : spdk_iobuf_channel_fini(&mod1_ch[0]);
455 : 6 : poll_threads();
456 : 6 : set_thread(1);
457 [ + - + - ]: 6 : spdk_iobuf_channel_fini(&mod0_ch[1]);
458 : 6 : poll_threads();
459 [ + - + - ]: 6 : spdk_iobuf_channel_fini(&mod1_ch[1]);
460 : 6 : poll_threads();
461 : :
462 : 6 : spdk_iobuf_finish(ut_iobuf_finish_cb, &finish);
463 : 6 : poll_threads();
464 : :
465 : 6 : CU_ASSERT_EQUAL(finish, 1);
466 : :
467 : 6 : free_threads();
468 : 6 : free_cores();
469 : 6 : }
470 : :
471 : : static void
472 : 6 : iobuf_cache(void)
473 : : {
474 : 6 : struct spdk_iobuf_opts opts = {
475 : : .small_pool_count = 4,
476 : : .large_pool_count = 4,
477 : : .small_bufsize = SMALL_BUFSIZE,
478 : : .large_bufsize = LARGE_BUFSIZE,
479 : : };
480 : 5 : struct spdk_iobuf_channel iobuf_ch[2];
481 : 1 : struct ut_iobuf_entry *entry;
482 : 6 : struct ut_iobuf_entry mod0_entries[] = {
483 : : { .thread_id = 0, .module = "ut_module0", },
484 : : { .thread_id = 0, .module = "ut_module0", },
485 : : { .thread_id = 0, .module = "ut_module0", },
486 : : { .thread_id = 0, .module = "ut_module0", },
487 : : };
488 : 6 : struct ut_iobuf_entry mod1_entries[] = {
489 : : { .thread_id = 0, .module = "ut_module1", },
490 : : { .thread_id = 0, .module = "ut_module1", },
491 : : };
492 : 6 : int rc, finish = 0;
493 : 1 : uint32_t i, j, bufsize;
494 : :
495 : 6 : allocate_cores(1);
496 : 6 : allocate_threads(1);
497 : :
498 : 6 : set_thread(0);
499 : :
500 : : /* We cannot use spdk_iobuf_set_opts(), as it won't allow us to use such small pools */
501 : 6 : g_iobuf.opts = opts;
502 : 6 : rc = spdk_iobuf_initialize();
503 : 6 : CU_ASSERT_EQUAL(rc, 0);
504 : :
505 : 6 : rc = spdk_iobuf_register_module("ut_module0");
506 : 6 : CU_ASSERT_EQUAL(rc, 0);
507 : :
508 : 6 : rc = spdk_iobuf_register_module("ut_module1");
509 : 6 : CU_ASSERT_EQUAL(rc, 0);
510 : :
511 : : /* First check that channel initialization fails when it's not possible to fill in the cache
512 : : * from the pool.
513 : : */
514 [ + - + - ]: 6 : rc = spdk_iobuf_channel_init(&iobuf_ch[0], "ut_module0", 5, 1);
515 : 6 : CU_ASSERT_EQUAL(rc, -ENOMEM);
516 [ + - + - ]: 6 : rc = spdk_iobuf_channel_init(&iobuf_ch[0], "ut_module0", 1, 5);
517 : 6 : CU_ASSERT_EQUAL(rc, -ENOMEM);
518 : :
519 [ + - + - ]: 6 : rc = spdk_iobuf_channel_init(&iobuf_ch[0], "ut_module0", 4, 4);
520 : 6 : CU_ASSERT_EQUAL(rc, 0);
521 [ + - + - ]: 6 : rc = spdk_iobuf_channel_init(&iobuf_ch[1], "ut_module1", 4, 4);
522 : 6 : CU_ASSERT_EQUAL(rc, -ENOMEM);
523 : :
524 [ + - + - ]: 6 : spdk_iobuf_channel_fini(&iobuf_ch[0]);
525 : 6 : poll_threads();
526 : :
527 : : /* Initialize one channel with cache, acquire buffers, and check that a second one can be
528 : : * created once the buffers acquired from the first one are returned to the pool
529 : : */
530 [ + - + - ]: 6 : rc = spdk_iobuf_channel_init(&iobuf_ch[0], "ut_module0", 2, 2);
531 : 6 : CU_ASSERT_EQUAL(rc, 0);
532 : :
533 [ + + ]: 24 : for (i = 0; i < 3; ++i) {
534 [ + - + - : 18 : mod0_entries[i].buf = spdk_iobuf_get(&iobuf_ch[0], LARGE_BUFSIZE, &mod0_entries[i].iobuf,
+ - + - +
- + - + -
+ - + - ]
535 : : ut_iobuf_get_buf_cb);
536 [ + - + - : 18 : CU_ASSERT_PTR_NOT_NULL(mod0_entries[i].buf);
+ - + - ]
537 : 3 : }
538 : :
539 : : /* The channels can be temporarily greedy, holding more buffers than their configured cache
540 : : * size. We can only guarantee that we can create a channel if all outstanding buffers
541 : : * have been returned. */
542 [ + + ]: 24 : for (i = 0; i < 3; ++i) {
543 [ + - + - : 18 : spdk_iobuf_put(&iobuf_ch[0], mod0_entries[i].buf, LARGE_BUFSIZE);
+ - + - +
- + - ]
544 : 3 : }
545 : :
546 : : /* The last buffer should be released back to the pool, so we should be able to create a new
547 : : * channel
548 : : */
549 [ + - + - ]: 6 : rc = spdk_iobuf_channel_init(&iobuf_ch[1], "ut_module1", 2, 2);
550 : 6 : CU_ASSERT_EQUAL(rc, 0);
551 : :
552 [ + - + - ]: 6 : spdk_iobuf_channel_fini(&iobuf_ch[0]);
553 [ + - + - ]: 6 : spdk_iobuf_channel_fini(&iobuf_ch[1]);
554 : 6 : poll_threads();
555 : :
556 : : /* Check that the pool is only used when the cache is empty and that the cache guarantees a
557 : : * certain set of buffers
558 : : */
559 [ + - + - ]: 6 : rc = spdk_iobuf_channel_init(&iobuf_ch[0], "ut_module0", 2, 2);
560 : 6 : CU_ASSERT_EQUAL(rc, 0);
561 [ + - + - ]: 6 : rc = spdk_iobuf_channel_init(&iobuf_ch[1], "ut_module1", 1, 1);
562 : 6 : CU_ASSERT_EQUAL(rc, 0);
563 : :
564 : 6 : uint32_t buffer_sizes[] = { SMALL_BUFSIZE, LARGE_BUFSIZE };
565 [ + + ]: 18 : for (i = 0; i < SPDK_COUNTOF(buffer_sizes); ++i) {
566 [ + - + - : 12 : bufsize = buffer_sizes[i];
+ - ]
567 : :
568 [ + + ]: 48 : for (j = 0; j < 3; ++j) {
569 [ + - + - ]: 36 : entry = &mod0_entries[j];
570 [ + - + - : 36 : entry->buf = spdk_iobuf_get(&iobuf_ch[0], bufsize, &entry->iobuf,
+ - + - +
- ]
571 : : ut_iobuf_get_buf_cb);
572 [ + - + - ]: 36 : CU_ASSERT_PTR_NOT_NULL(entry->buf);
573 : 6 : }
574 : :
575 [ + - + - : 12 : mod1_entries[0].buf = spdk_iobuf_get(&iobuf_ch[1], bufsize, &mod1_entries[0].iobuf,
+ - + - +
- + - +
- ]
576 : : ut_iobuf_get_buf_cb);
577 [ + - + - : 12 : CU_ASSERT_PTR_NOT_NULL(mod1_entries[0].buf);
+ - ]
578 : :
579 : : /* The whole pool is exhausted now */
580 [ + - + - : 12 : mod1_entries[1].buf = spdk_iobuf_get(&iobuf_ch[1], bufsize, &mod1_entries[1].iobuf,
+ - + - +
- + - + -
+ - + - ]
581 : : ut_iobuf_get_buf_cb);
582 [ + - + - : 12 : CU_ASSERT_PTR_NULL(mod1_entries[1].buf);
+ - + - ]
583 [ + - + - : 12 : mod0_entries[3].buf = spdk_iobuf_get(&iobuf_ch[0], bufsize, &mod0_entries[3].iobuf,
+ - + - +
- + - + -
+ - + - ]
584 : : ut_iobuf_get_buf_cb);
585 [ + - + - : 12 : CU_ASSERT_PTR_NULL(mod0_entries[3].buf);
+ - + - ]
586 : :
587 : : /* If there are outstanding requests waiting for a buffer, they should have priority
588 : : * over filling in the cache, even if they're from different modules.
589 : : */
590 [ + - + - : 12 : spdk_iobuf_put(&iobuf_ch[0], mod0_entries[2].buf, bufsize);
+ - + - +
- + - ]
591 : : /* Also make sure the queue is FIFO and doesn't care about which module requested
592 : : * and which module released the buffer.
593 : : */
594 [ + - + - : 12 : CU_ASSERT_PTR_NOT_NULL(mod1_entries[1].buf);
+ - + - ]
595 [ + - + - : 12 : CU_ASSERT_PTR_NULL(mod0_entries[3].buf);
+ - + - ]
596 : :
597 : : /* Return the buffers back */
598 [ + - + - : 12 : spdk_iobuf_entry_abort(&iobuf_ch[0], &mod0_entries[3].iobuf, bufsize);
+ - + - +
- ]
599 [ + + ]: 36 : for (j = 0; j < 2; ++j) {
600 [ + - + - : 24 : spdk_iobuf_put(&iobuf_ch[0], mod0_entries[j].buf, bufsize);
+ - + - +
- + - ]
601 [ + - + - : 24 : spdk_iobuf_put(&iobuf_ch[1], mod1_entries[j].buf, bufsize);
+ - + - +
- + - ]
602 : 4 : }
603 : 2 : }
604 : :
605 [ + - + - ]: 6 : spdk_iobuf_channel_fini(&iobuf_ch[0]);
606 [ + - + - ]: 6 : spdk_iobuf_channel_fini(&iobuf_ch[1]);
607 : 6 : poll_threads();
608 : :
609 : 6 : spdk_iobuf_finish(ut_iobuf_finish_cb, &finish);
610 : 6 : poll_threads();
611 : :
612 : 6 : CU_ASSERT_EQUAL(finish, 1);
613 : :
614 : 6 : free_threads();
615 : 6 : free_cores();
616 : 6 : }
617 : :
618 : : int
619 : 6 : main(int argc, char **argv)
620 : : {
621 : 6 : CU_pSuite suite = NULL;
622 : 1 : unsigned int num_failures;
623 : :
624 : 6 : CU_initialize_registry();
625 : :
626 : 6 : suite = CU_add_suite("io_channel", NULL, NULL);
627 : 6 : CU_ADD_TEST(suite, iobuf);
628 : 6 : CU_ADD_TEST(suite, iobuf_cache);
629 : :
630 : 6 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
631 : 6 : CU_cleanup_registry();
632 : 7 : return num_failures;
633 : 1 : }
|