Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2020 Intel Corporation.
3 : : * All rights reserved.
4 : : * Copyright (c) 2021 Mellanox Technologies LTD. All rights reserved.
5 : : */
6 : :
7 : : #include "spdk_internal/cunit.h"
8 : :
9 : : #include "nvme/nvme_poll_group.c"
10 : : #include "common/lib/test_env.c"
11 : :
12 : 4 : SPDK_LOG_REGISTER_COMPONENT(nvme)
13 : :
14 : : struct spdk_nvme_transport {
15 : : const char name[32];
16 : : TAILQ_ENTRY(spdk_nvme_transport) link;
17 : : };
18 : :
19 : : struct spdk_nvme_transport t1 = {
20 : : .name = "transport1",
21 : : };
22 : :
23 : : struct spdk_nvme_transport t2 = {
24 : : .name = "transport2",
25 : : };
26 : :
27 : : struct spdk_nvme_transport t3 = {
28 : : .name = "transport3",
29 : : };
30 : :
31 : : struct spdk_nvme_transport t4 = {
32 : : .name = "transport4",
33 : : };
34 : :
35 : : struct spdk_nvme_ctrlr c1 = {
36 : : .opts.enable_interrupts = 0,
37 : : };
38 : :
39 : : struct spdk_nvme_ctrlr c2 = {
40 : : .opts.enable_interrupts = 1,
41 : : };
42 : :
43 : : int64_t g_process_completions_return_value = 0;
44 : : int g_destroy_return_value = 0;
45 : :
46 : : TAILQ_HEAD(nvme_transport_list, spdk_nvme_transport) g_spdk_nvme_transports =
47 : : TAILQ_HEAD_INITIALIZER(g_spdk_nvme_transports);
48 : :
49 [ # # # # ]: 0 : DEFINE_STUB(nvme_transport_qpair_get_optimal_poll_group,
50 : : struct spdk_nvme_transport_poll_group *,
51 : : (const struct spdk_nvme_transport *transport,
52 : : struct spdk_nvme_qpair *qpair),
53 : : NULL);
54 [ - + # # ]: 24 : DEFINE_STUB(nvme_transport_get_trtype,
55 : : enum spdk_nvme_transport_type,
56 : : (const struct spdk_nvme_transport *transport),
57 : : SPDK_NVME_TRANSPORT_PCIE);
58 : :
59 [ # # # # ]: 0 : DEFINE_STUB(spdk_nvme_qpair_get_fd, int, (struct spdk_nvme_qpair *qpair,
60 : : struct spdk_event_handler_opts *opts), 0);
61 [ # # # # ]: 0 : DEFINE_STUB(spdk_nvme_ctrlr_get_transport_id,
62 : : const struct spdk_nvme_transport_id *,
63 : : (struct spdk_nvme_ctrlr *ctrlr), NULL);
64 : : int
65 : 12 : nvme_transport_poll_group_get_stats(struct spdk_nvme_transport_poll_group *tgroup,
66 : : struct spdk_nvme_transport_poll_group_stat **stats)
67 : : {
68 : 12 : *stats = calloc(1, sizeof(**stats));
69 [ + + ]: 12 : SPDK_CU_ASSERT_FATAL(*stats != NULL);
70 : 12 : (*stats)->trtype = nvme_transport_get_trtype(NULL);
71 : :
72 : 12 : return 0;
73 : : }
74 : :
75 : : void
76 : 12 : nvme_transport_poll_group_free_stats(struct spdk_nvme_transport_poll_group *tgroup,
77 : : struct spdk_nvme_transport_poll_group_stat *stats)
78 : : {
79 : 12 : free(stats);
80 : 12 : }
81 : :
82 : : static void
83 : 0 : unit_test_disconnected_qpair_cb(struct spdk_nvme_qpair *qpair, void *poll_group_ctx)
84 : : {
85 : :
86 : 0 : }
87 : :
88 : : const struct spdk_nvme_transport *
89 : 32 : nvme_get_first_transport(void)
90 : : {
91 : 32 : return TAILQ_FIRST(&g_spdk_nvme_transports);
92 : : }
93 : :
94 : : const struct spdk_nvme_transport *
95 : 40 : nvme_get_next_transport(const struct spdk_nvme_transport *transport)
96 : : {
97 : 40 : return TAILQ_NEXT(transport, link);
98 : : }
99 : :
100 : : int
101 : 0 : nvme_transport_poll_group_disconnect_qpair(struct spdk_nvme_qpair *qpair)
102 : : {
103 : : struct spdk_nvme_transport_poll_group *tgroup;
104 : : struct spdk_nvme_qpair *iter_qp, *tmp_iter_qp;
105 : :
106 : 0 : tgroup = qpair->poll_group;
107 : :
108 [ # # # # ]: 0 : STAILQ_FOREACH_SAFE(iter_qp, &tgroup->connected_qpairs, poll_group_stailq, tmp_iter_qp) {
109 [ # # ]: 0 : if (qpair == iter_qp) {
110 [ # # # # : 0 : STAILQ_REMOVE(&tgroup->connected_qpairs, qpair, spdk_nvme_qpair, poll_group_stailq);
# # # # ]
111 : 0 : STAILQ_INSERT_TAIL(&tgroup->disconnected_qpairs, qpair, poll_group_stailq);
112 : 0 : return 0;
113 : : }
114 : 0 : }
115 : :
116 [ # # ]: 0 : STAILQ_FOREACH(iter_qp, &tgroup->disconnected_qpairs, poll_group_stailq) {
117 [ # # ]: 0 : if (qpair == iter_qp) {
118 : 0 : return 0;
119 : : }
120 : 0 : }
121 : :
122 : 0 : return -EINVAL;
123 : 0 : }
124 : :
125 : : int
126 : 4 : nvme_transport_poll_group_connect_qpair(struct spdk_nvme_qpair *qpair)
127 : : {
128 : : struct spdk_nvme_transport_poll_group *tgroup;
129 : : struct spdk_nvme_qpair *iter_qp, *tmp_iter_qp;
130 : :
131 : 4 : tgroup = qpair->poll_group;
132 : :
133 [ + + - + ]: 4 : STAILQ_FOREACH_SAFE(iter_qp, &tgroup->disconnected_qpairs, poll_group_stailq, tmp_iter_qp) {
134 [ # # ]: 0 : if (qpair == iter_qp) {
135 [ # # # # : 0 : STAILQ_REMOVE(&tgroup->disconnected_qpairs, qpair, spdk_nvme_qpair, poll_group_stailq);
# # # # ]
136 : 0 : STAILQ_INSERT_TAIL(&tgroup->connected_qpairs, qpair, poll_group_stailq);
137 : 0 : return 0;
138 : : }
139 : 0 : }
140 : :
141 [ + - ]: 4 : STAILQ_FOREACH(iter_qp, &tgroup->connected_qpairs, poll_group_stailq) {
142 [ + + ]: 4 : if (qpair == iter_qp) {
143 : 4 : return 0;
144 : : }
145 : 0 : }
146 : :
147 : 0 : return -EINVAL;
148 : 1 : }
149 : :
150 : : struct spdk_nvme_transport_poll_group *
151 : 24 : nvme_transport_poll_group_create(const struct spdk_nvme_transport *transport)
152 : : {
153 : 24 : struct spdk_nvme_transport_poll_group *group = NULL;
154 : :
155 : : /* TODO: separate this transport function table from the transport specific one. */
156 : 24 : group = calloc(1, sizeof(*group));
157 [ + - ]: 24 : if (group) {
158 : 24 : group->transport = transport;
159 : 24 : STAILQ_INIT(&group->connected_qpairs);
160 : 24 : STAILQ_INIT(&group->disconnected_qpairs);
161 : 6 : }
162 : :
163 : 24 : return group;
164 : : }
165 : :
166 : : int
167 : 8 : nvme_transport_poll_group_destroy(struct spdk_nvme_transport_poll_group *tgroup)
168 : : {
169 : 8 : return g_destroy_return_value;
170 : : }
171 : :
172 : : int
173 : 36 : nvme_transport_poll_group_add(struct spdk_nvme_transport_poll_group *tgroup,
174 : : struct spdk_nvme_qpair *qpair)
175 : : {
176 : 36 : STAILQ_INSERT_TAIL(&tgroup->connected_qpairs, qpair, poll_group_stailq);
177 : 36 : qpair->poll_group = tgroup;
178 : :
179 : 36 : return 0;
180 : : }
181 : :
182 : : int
183 : 32 : nvme_transport_poll_group_remove(struct spdk_nvme_transport_poll_group *tgroup,
184 : : struct spdk_nvme_qpair *qpair)
185 : : {
186 : : struct spdk_nvme_qpair *iter_qp, *tmp_iter_qp;
187 : :
188 [ + - + - ]: 32 : STAILQ_FOREACH_SAFE(iter_qp, &tgroup->connected_qpairs, poll_group_stailq, tmp_iter_qp) {
189 [ + + ]: 32 : if (qpair == iter_qp) {
190 [ + + + + : 32 : STAILQ_REMOVE(&tgroup->connected_qpairs, qpair, spdk_nvme_qpair, poll_group_stailq);
- - - - ]
191 : 32 : return 0;
192 : : }
193 : 0 : }
194 : :
195 [ # # # # ]: 0 : STAILQ_FOREACH_SAFE(iter_qp, &tgroup->disconnected_qpairs, poll_group_stailq, tmp_iter_qp) {
196 [ # # ]: 0 : if (qpair == iter_qp) {
197 [ # # # # : 0 : STAILQ_REMOVE(&tgroup->disconnected_qpairs, qpair, spdk_nvme_qpair, poll_group_stailq);
# # # # ]
198 : 0 : return 0;
199 : : }
200 : 0 : }
201 : :
202 : 0 : return -ENODEV;
203 : 8 : }
204 : :
205 : : int32_t
206 : 0 : spdk_nvme_qpair_process_completions(struct spdk_nvme_qpair *qpair, uint32_t max_completions)
207 : : {
208 : 0 : return g_process_completions_return_value;
209 : : }
210 : :
211 : : int64_t
212 : 4 : nvme_transport_poll_group_process_completions(struct spdk_nvme_transport_poll_group *group,
213 : : uint32_t completions_per_qpair, spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb)
214 : : {
215 : 4 : return g_process_completions_return_value;
216 : : }
217 : :
218 : : static void
219 : 4 : test_spdk_nvme_poll_group_create(void)
220 : : {
221 : : struct spdk_nvme_poll_group *group;
222 : :
223 : : /* basic case - create a poll group with no internal transport poll groups. */
224 : 4 : group = spdk_nvme_poll_group_create(NULL, NULL);
225 : :
226 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(group != NULL);
227 : 4 : CU_ASSERT(STAILQ_EMPTY(&group->tgroups));
228 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(spdk_nvme_poll_group_destroy(group) == 0);
229 : :
230 : 4 : TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, &t1, link);
231 : 4 : TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, &t2, link);
232 : 4 : TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, &t3, link);
233 : :
234 : : /* advanced case - create a poll group with three internal poll groups. */
235 : 4 : group = spdk_nvme_poll_group_create(NULL, NULL);
236 : 4 : CU_ASSERT(STAILQ_EMPTY(&group->tgroups));
237 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(spdk_nvme_poll_group_destroy(group) == 0);
238 : :
239 : : /* Failing case - failed to allocate a poll group. */
240 : 4 : MOCK_SET(calloc, NULL);
241 : 4 : group = spdk_nvme_poll_group_create(NULL, NULL);
242 : 4 : CU_ASSERT(group == NULL);
243 [ - + - + ]: 4 : MOCK_CLEAR(calloc);
244 : :
245 [ + - ]: 4 : TAILQ_REMOVE(&g_spdk_nvme_transports, &t1, link);
246 [ + - ]: 4 : TAILQ_REMOVE(&g_spdk_nvme_transports, &t2, link);
247 [ - + ]: 4 : TAILQ_REMOVE(&g_spdk_nvme_transports, &t3, link);
248 : 4 : }
249 : :
250 : : static void
251 : 4 : test_spdk_nvme_poll_group_add_remove(void)
252 : : {
253 : : struct spdk_nvme_poll_group *group;
254 : 4 : struct spdk_nvme_transport_poll_group *tgroup = NULL, *tmp_tgroup, *tgroup_1 = NULL,
255 : 4 : *tgroup_2 = NULL,
256 : 4 : *tgroup_4 = NULL;
257 : : struct spdk_nvme_qpair *qpair;
258 : 4 : struct spdk_nvme_qpair qpair1_1 = {0};
259 : 4 : struct spdk_nvme_qpair qpair1_2 = {0};
260 : 4 : struct spdk_nvme_qpair qpair2_1 = {0};
261 : 4 : struct spdk_nvme_qpair qpair2_2 = {0};
262 : 4 : struct spdk_nvme_qpair qpair4_1 = {0};
263 : 4 : struct spdk_nvme_qpair qpair4_2 = {0};
264 : 4 : int i = 0;
265 : :
266 : 4 : TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, &t1, link);
267 : 4 : TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, &t2, link);
268 : 4 : TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, &t3, link);
269 : :
270 : 4 : group = spdk_nvme_poll_group_create(NULL, NULL);
271 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(group != NULL);
272 [ - + ]: 4 : CU_ASSERT(group->enable_interrupts_is_valid == false);
273 [ - + ]: 4 : CU_ASSERT(group->enable_interrupts == false);
274 : 4 : CU_ASSERT(STAILQ_EMPTY(&group->tgroups));
275 : :
276 : : /* Add qpairs from different controllers. One with interrupts other without. */
277 : 4 : qpair1_1.transport = &t1;
278 : 4 : qpair1_1.ctrlr = &c1;
279 : 4 : qpair1_1.state = NVME_QPAIR_DISCONNECTED;
280 : 4 : qpair1_2.transport = &t1;
281 : 4 : qpair1_2.ctrlr = &c2;
282 : 4 : qpair1_2.state = NVME_QPAIR_DISCONNECTED;
283 : 4 : CU_ASSERT(spdk_nvme_poll_group_add(group, &qpair1_1) == 0);
284 : 4 : CU_ASSERT(spdk_nvme_poll_group_add(group, &qpair1_2) == -EINVAL);
285 [ - + ]: 4 : CU_ASSERT(group->enable_interrupts_is_valid == true);
286 [ - + ]: 4 : CU_ASSERT(group->enable_interrupts == false);
287 [ + + ]: 8 : STAILQ_FOREACH(tmp_tgroup, &group->tgroups, link) {
288 [ + + ]: 4 : if (tmp_tgroup->transport == &t1) {
289 : 4 : tgroup = tmp_tgroup;
290 : 1 : } else {
291 : 0 : CU_ASSERT(STAILQ_EMPTY(&tmp_tgroup->connected_qpairs));
292 : : }
293 : 4 : i++;
294 : 1 : }
295 : 4 : CU_ASSERT(i == 1);
296 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(tgroup != NULL);
297 : 4 : qpair = STAILQ_FIRST(&tgroup->connected_qpairs);
298 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(qpair == &qpair1_1);
299 : 4 : qpair = STAILQ_NEXT(qpair, poll_group_stailq);
300 : 4 : CU_ASSERT(qpair == NULL);
301 : :
302 : : /* Add second qpair from the same controller as the first. */
303 : 4 : qpair1_2.ctrlr = &c1;
304 : 4 : CU_ASSERT(spdk_nvme_poll_group_add(group, &qpair1_2) == 0);
305 : 4 : i = 0;
306 [ + + ]: 8 : STAILQ_FOREACH(tmp_tgroup, &group->tgroups, link) {
307 [ + + ]: 4 : if (tmp_tgroup->transport == &t1) {
308 : 4 : tgroup = tmp_tgroup;
309 : 1 : } else {
310 : 0 : CU_ASSERT(STAILQ_EMPTY(&tmp_tgroup->connected_qpairs));
311 : : }
312 : 4 : i++;
313 : 1 : }
314 : 4 : CU_ASSERT(i == 1);
315 : 4 : qpair = STAILQ_FIRST(&tgroup->connected_qpairs);
316 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(qpair == &qpair1_1);
317 : 4 : qpair = STAILQ_NEXT(qpair, poll_group_stailq);
318 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(qpair == &qpair1_2);
319 : 4 : qpair = STAILQ_NEXT(qpair, poll_group_stailq);
320 : 4 : CU_ASSERT(qpair == NULL);
321 : :
322 : 4 : i = 0;
323 : : /* Remove both qpairs and delete the transport poll group. */
324 : 4 : CU_ASSERT(spdk_nvme_poll_group_remove(group, &qpair1_1) == 0);
325 : 4 : CU_ASSERT(spdk_nvme_poll_group_remove(group, &qpair1_2) == 0);
326 [ + + + + ]: 8 : STAILQ_FOREACH_SAFE(tgroup, &group->tgroups, link, tmp_tgroup) {
327 : 4 : CU_ASSERT(STAILQ_EMPTY(&tgroup->connected_qpairs));
328 [ + + + + : 4 : STAILQ_REMOVE(&group->tgroups, tgroup, spdk_nvme_transport_poll_group, link);
- - - - ]
329 : 4 : free(tgroup);
330 : 4 : i++;
331 : 1 : }
332 : 4 : CU_ASSERT(i == 1);
333 : 4 : CU_ASSERT(STAILQ_EMPTY(&group->tgroups));
334 [ - + ]: 4 : CU_ASSERT(group->enable_interrupts == false);
335 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(spdk_nvme_poll_group_destroy(group) == 0);
336 : :
337 : 4 : group = spdk_nvme_poll_group_create(NULL, NULL);
338 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(group != NULL);
339 [ - + ]: 4 : CU_ASSERT(group->enable_interrupts_is_valid == false);
340 [ - + ]: 4 : CU_ASSERT(group->enable_interrupts == false);
341 : 4 : CU_ASSERT(STAILQ_EMPTY(&group->tgroups));
342 : :
343 : : /* Add qpairs to a single transport. */
344 : 4 : qpair1_1.transport = &t1;
345 : 4 : qpair1_1.ctrlr = &c1;
346 : 4 : qpair1_1.state = NVME_QPAIR_DISCONNECTED;
347 : 4 : qpair1_2.transport = &t1;
348 : 4 : qpair1_2.ctrlr = &c1;
349 : 4 : qpair1_2.state = NVME_QPAIR_ENABLED;
350 : 4 : CU_ASSERT(spdk_nvme_poll_group_add(group, &qpair1_1) == 0);
351 : 4 : CU_ASSERT(spdk_nvme_poll_group_add(group, &qpair1_2) == -EINVAL);
352 [ - + ]: 4 : CU_ASSERT(group->enable_interrupts_is_valid == true);
353 [ - + ]: 4 : CU_ASSERT(group->enable_interrupts == false);
354 : 4 : i = 0;
355 [ + + ]: 8 : STAILQ_FOREACH(tmp_tgroup, &group->tgroups, link) {
356 [ + + ]: 4 : if (tmp_tgroup->transport == &t1) {
357 : 4 : tgroup = tmp_tgroup;
358 : 1 : } else {
359 : 0 : CU_ASSERT(STAILQ_EMPTY(&tmp_tgroup->connected_qpairs));
360 : : }
361 : 4 : i++;
362 : 1 : }
363 : 4 : CU_ASSERT(i == 1);
364 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(tgroup != NULL);
365 : 4 : qpair = STAILQ_FIRST(&tgroup->connected_qpairs);
366 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(qpair == &qpair1_1);
367 : 4 : qpair = STAILQ_NEXT(qpair, poll_group_stailq);
368 : 4 : CU_ASSERT(qpair == NULL);
369 : :
370 : : /* Add qpairs to a second transport. */
371 : 4 : qpair2_1.transport = &t2;
372 : 4 : qpair2_1.ctrlr = &c1;
373 : 4 : qpair2_2.transport = &t2;
374 : 4 : qpair2_2.ctrlr = &c1;
375 : 4 : CU_ASSERT(spdk_nvme_poll_group_add(group, &qpair2_1) == 0);
376 : 4 : CU_ASSERT(spdk_nvme_poll_group_add(group, &qpair2_2) == 0);
377 : 4 : qpair4_1.transport = &t4;
378 : 4 : qpair4_2.transport = &t4;
379 : 4 : qpair4_1.ctrlr = &c1;
380 : 4 : qpair4_2.ctrlr = &c1;
381 : : /* Add qpairs for a transport that doesn't exist. */
382 : 4 : CU_ASSERT(spdk_nvme_poll_group_add(group, &qpair4_1) == -ENODEV);
383 : 4 : CU_ASSERT(spdk_nvme_poll_group_add(group, &qpair4_2) == -ENODEV);
384 : 4 : i = 0;
385 [ + + ]: 12 : STAILQ_FOREACH(tmp_tgroup, &group->tgroups, link) {
386 [ + + ]: 8 : if (tmp_tgroup->transport == &t1) {
387 : 4 : tgroup_1 = tmp_tgroup;
388 [ + + ]: 5 : } else if (tmp_tgroup->transport == &t2) {
389 : 4 : tgroup_2 = tmp_tgroup;
390 : 1 : } else {
391 : 0 : CU_ASSERT(STAILQ_EMPTY(&tmp_tgroup->connected_qpairs));
392 : : }
393 : 8 : i++;
394 : 2 : }
395 : 4 : CU_ASSERT(i == 2);
396 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(tgroup_1 != NULL);
397 : 4 : qpair = STAILQ_FIRST(&tgroup_1->connected_qpairs);
398 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(qpair == &qpair1_1);
399 : 4 : qpair = STAILQ_NEXT(qpair, poll_group_stailq);
400 : 4 : CU_ASSERT(qpair == NULL);
401 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(tgroup_2 != NULL);
402 : 4 : qpair = STAILQ_FIRST(&tgroup_2->connected_qpairs);
403 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(qpair == &qpair2_1);
404 : 4 : qpair = STAILQ_NEXT(qpair, poll_group_stailq);
405 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(qpair == &qpair2_2);
406 : 4 : qpair = STAILQ_NEXT(qpair, poll_group_stailq);
407 : 4 : CU_ASSERT(qpair == NULL);
408 : :
409 : : /* Try removing a qpair that belongs to a transport not in our poll group. */
410 : 4 : CU_ASSERT(spdk_nvme_poll_group_remove(group, &qpair4_1) == -ENODEV);
411 : :
412 : 4 : TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, &t4, link);
413 : 4 : CU_ASSERT(spdk_nvme_poll_group_add(group, &qpair4_1) == 0);
414 : 4 : CU_ASSERT(spdk_nvme_poll_group_add(group, &qpair4_2) == 0);
415 [ + + ]: 16 : STAILQ_FOREACH(tmp_tgroup, &group->tgroups, link) {
416 [ + + ]: 12 : if (tmp_tgroup->transport == &t1) {
417 : 4 : tgroup_1 = tmp_tgroup;
418 [ + + ]: 9 : } else if (tmp_tgroup->transport == &t2) {
419 : 4 : tgroup_2 = tmp_tgroup;
420 [ + + ]: 5 : } else if (tmp_tgroup->transport == &t4) {
421 : 4 : tgroup_4 = tmp_tgroup;
422 : 1 : } else {
423 : 0 : CU_ASSERT(STAILQ_EMPTY(&tmp_tgroup->connected_qpairs));
424 : : }
425 : 3 : }
426 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(tgroup_1 != NULL);
427 : 4 : qpair = STAILQ_FIRST(&tgroup_1->connected_qpairs);
428 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(qpair == &qpair1_1);
429 : 4 : qpair = STAILQ_NEXT(qpair, poll_group_stailq);
430 : 4 : CU_ASSERT(qpair == NULL);
431 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(tgroup_2 != NULL);
432 : 4 : qpair = STAILQ_FIRST(&tgroup_2->connected_qpairs);
433 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(qpair == &qpair2_1);
434 : 4 : qpair = STAILQ_NEXT(qpair, poll_group_stailq);
435 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(qpair == &qpair2_2);
436 : 4 : qpair = STAILQ_NEXT(qpair, poll_group_stailq);
437 : 4 : CU_ASSERT(qpair == NULL);
438 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(tgroup_4 != NULL);
439 : 4 : qpair = STAILQ_FIRST(&tgroup_4->connected_qpairs);
440 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(qpair == &qpair4_1);
441 : 4 : qpair = STAILQ_NEXT(qpair, poll_group_stailq);
442 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(qpair == &qpair4_2);
443 : 4 : qpair = STAILQ_NEXT(qpair, poll_group_stailq);
444 : 4 : CU_ASSERT(qpair == NULL);
445 : :
446 : : /* remove all qpairs */
447 : 4 : CU_ASSERT(spdk_nvme_poll_group_remove(group, &qpair1_1) == 0);
448 : 4 : CU_ASSERT(spdk_nvme_poll_group_remove(group, &qpair2_1) == 0);
449 : 4 : CU_ASSERT(spdk_nvme_poll_group_remove(group, &qpair2_2) == 0);
450 : 4 : CU_ASSERT(spdk_nvme_poll_group_remove(group, &qpair4_1) == 0);
451 : 4 : CU_ASSERT(spdk_nvme_poll_group_remove(group, &qpair4_2) == 0);
452 : : /* Confirm the fourth transport group was created. */
453 : 4 : i = 0;
454 [ + + + + ]: 16 : STAILQ_FOREACH_SAFE(tgroup, &group->tgroups, link, tmp_tgroup) {
455 : 12 : CU_ASSERT(STAILQ_EMPTY(&tgroup->connected_qpairs));
456 [ + + + + : 12 : STAILQ_REMOVE(&group->tgroups, tgroup, spdk_nvme_transport_poll_group, link);
- - - - ]
457 : 12 : free(tgroup);
458 : 12 : i++;
459 : 3 : }
460 : 4 : CU_ASSERT(i == 3);
461 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(spdk_nvme_poll_group_destroy(group) == 0);
462 : :
463 [ + - ]: 4 : TAILQ_REMOVE(&g_spdk_nvme_transports, &t1, link);
464 [ + - ]: 4 : TAILQ_REMOVE(&g_spdk_nvme_transports, &t2, link);
465 [ + - ]: 4 : TAILQ_REMOVE(&g_spdk_nvme_transports, &t3, link);
466 [ - + ]: 4 : TAILQ_REMOVE(&g_spdk_nvme_transports, &t4, link);
467 : 4 : }
468 : :
469 : : static void
470 : 4 : test_spdk_nvme_poll_group_process_completions(void)
471 : : {
472 : : struct spdk_nvme_poll_group *group;
473 : : struct spdk_nvme_transport_poll_group *tgroup, *tmp_tgroup;
474 : 4 : struct spdk_nvme_qpair qpair1_1 = {0};
475 : :
476 : 4 : group = spdk_nvme_poll_group_create(NULL, NULL);
477 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(group != NULL);
478 : :
479 : : /* If we don't have any transport poll groups, we shouldn't get any completions. */
480 : 4 : g_process_completions_return_value = 32;
481 : 4 : CU_ASSERT(spdk_nvme_poll_group_process_completions(group, 128,
482 : : unit_test_disconnected_qpair_cb) == 0);
483 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(spdk_nvme_poll_group_destroy(group) == 0);
484 : :
485 : 4 : TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, &t1, link);
486 : 4 : TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, &t2, link);
487 : 4 : TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, &t3, link);
488 : :
489 : : /* try it with three transport poll groups. */
490 : 4 : group = spdk_nvme_poll_group_create(NULL, NULL);
491 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(group != NULL);
492 : 4 : qpair1_1.state = NVME_QPAIR_DISCONNECTED;
493 : 4 : qpair1_1.transport = &t1;
494 : 4 : qpair1_1.ctrlr = &c1;
495 : 4 : CU_ASSERT(spdk_nvme_poll_group_add(group, &qpair1_1) == 0);
496 : 4 : qpair1_1.state = NVME_QPAIR_ENABLED;
497 : 4 : CU_ASSERT(nvme_poll_group_connect_qpair(&qpair1_1) == 0);
498 : 4 : CU_ASSERT(spdk_nvme_poll_group_process_completions(group, 128,
499 : : unit_test_disconnected_qpair_cb) == 32);
500 : 4 : CU_ASSERT(spdk_nvme_poll_group_remove(group, &qpair1_1) == 0);
501 [ + + + + ]: 8 : STAILQ_FOREACH_SAFE(tgroup, &group->tgroups, link, tmp_tgroup) {
502 : 4 : CU_ASSERT(STAILQ_EMPTY(&tgroup->connected_qpairs));
503 [ + + + + : 4 : STAILQ_REMOVE(&group->tgroups, tgroup, spdk_nvme_transport_poll_group, link);
- - - - ]
504 : 4 : free(tgroup);
505 : 1 : }
506 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(spdk_nvme_poll_group_destroy(group) == 0);
507 : :
508 [ + - ]: 4 : TAILQ_REMOVE(&g_spdk_nvme_transports, &t1, link);
509 [ + - ]: 4 : TAILQ_REMOVE(&g_spdk_nvme_transports, &t2, link);
510 [ - + ]: 4 : TAILQ_REMOVE(&g_spdk_nvme_transports, &t3, link);
511 : 4 : }
512 : :
513 : : static void
514 : 4 : test_spdk_nvme_poll_group_destroy(void)
515 : : {
516 : : struct spdk_nvme_poll_group *group;
517 : : struct spdk_nvme_transport_poll_group *tgroup, *tgroup_1, *tgroup_2;
518 : 4 : struct spdk_nvme_qpair qpair1_1 = {0};
519 : 4 : int num_tgroups = 0;
520 : :
521 : : /* Simple destruction of empty poll group. */
522 : 4 : group = spdk_nvme_poll_group_create(NULL, NULL);
523 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(group != NULL);
524 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(spdk_nvme_poll_group_destroy(group) == 0);
525 : :
526 : 4 : TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, &t1, link);
527 : 4 : TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, &t2, link);
528 : 4 : TAILQ_INSERT_TAIL(&g_spdk_nvme_transports, &t3, link);
529 : 4 : group = spdk_nvme_poll_group_create(NULL, NULL);
530 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(group != NULL);
531 : :
532 : 4 : qpair1_1.transport = &t1;
533 : 4 : qpair1_1.ctrlr = &c1;
534 : 4 : CU_ASSERT(spdk_nvme_poll_group_add(group, &qpair1_1) == 0);
535 : :
536 : : /* Don't remove busy poll groups. */
537 : 4 : g_destroy_return_value = -EBUSY;
538 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(spdk_nvme_poll_group_destroy(group) == -EBUSY);
539 [ + + ]: 8 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
540 : 4 : num_tgroups++;
541 : 1 : }
542 : 4 : CU_ASSERT(num_tgroups == 1);
543 : :
544 : : /* destroy poll group with internal poll groups. */
545 : 4 : g_destroy_return_value = 0;
546 : 4 : tgroup_1 = STAILQ_FIRST(&group->tgroups);
547 : 4 : tgroup_2 = STAILQ_NEXT(tgroup_1, link);
548 : 4 : CU_ASSERT(tgroup_2 == NULL)
549 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(spdk_nvme_poll_group_destroy(group) == 0);
550 : 4 : free(tgroup_1);
551 : 4 : }
552 : :
553 : : static void
554 : 4 : test_spdk_nvme_poll_group_get_free_stats(void)
555 : : {
556 : 4 : struct spdk_nvme_poll_group group = {};
557 : 4 : struct spdk_nvme_poll_group_stat *stats = NULL;
558 : 4 : struct spdk_nvme_transport_poll_group tgroup[3] = {};
559 : : int rc, i;
560 : :
561 : : /* Multiple tgroups */
562 : 4 : STAILQ_INIT(&group.tgroups);
563 [ + + ]: 16 : for (i = 0; i < 3; i++) {
564 : 12 : STAILQ_INSERT_TAIL(&group.tgroups, &tgroup[i], link);
565 : 3 : }
566 : :
567 : 4 : rc = spdk_nvme_poll_group_get_stats(&group, &stats);
568 : 4 : CU_ASSERT(rc == 0);
569 : 4 : CU_ASSERT(stats->num_transports == 3);
570 : :
571 : 4 : spdk_nvme_poll_group_free_stats(&group, stats);
572 [ + + ]: 16 : for (i = 0; i < 3; i++) {
573 [ + + + + : 12 : STAILQ_REMOVE(&group.tgroups, &tgroup[i], spdk_nvme_transport_poll_group, link);
- - - - ]
574 : 3 : }
575 [ + + ]: 4 : SPDK_CU_ASSERT_FATAL(STAILQ_EMPTY(&group.tgroups));
576 : :
577 : : /* No available tgroup */
578 : 4 : rc = spdk_nvme_poll_group_get_stats(&group, &stats);
579 : 4 : CU_ASSERT(rc == -ENOTSUP);
580 : 4 : }
581 : :
582 : : int
583 : 4 : main(int argc, char **argv)
584 : : {
585 : 4 : CU_pSuite suite = NULL;
586 : : unsigned int num_failures;
587 : :
588 [ - + ]: 4 : if (CU_initialize_registry() != CUE_SUCCESS) {
589 : 0 : return CU_get_error();
590 : : }
591 : :
592 : 4 : suite = CU_add_suite("nvme_ns_cmd", NULL, NULL);
593 [ + + ]: 4 : if (suite == NULL) {
594 : 0 : CU_cleanup_registry();
595 : 0 : return CU_get_error();
596 : : }
597 : :
598 [ + - ]: 3 : if (
599 [ + - + - ]: 8 : CU_add_test(suite, "nvme_poll_group_create_test", test_spdk_nvme_poll_group_create) == NULL ||
600 : 4 : CU_add_test(suite, "nvme_poll_group_add_remove_test",
601 [ + - ]: 4 : test_spdk_nvme_poll_group_add_remove) == NULL ||
602 : 4 : CU_add_test(suite, "nvme_poll_group_process_completions",
603 [ + - ]: 4 : test_spdk_nvme_poll_group_process_completions) == NULL ||
604 [ + + ]: 7 : CU_add_test(suite, "nvme_poll_group_destroy_test", test_spdk_nvme_poll_group_destroy) == NULL ||
605 : 4 : CU_add_test(suite, "nvme_poll_group_get_free_stats",
606 : 1 : test_spdk_nvme_poll_group_get_free_stats) == NULL
607 : : ) {
608 : 0 : CU_cleanup_registry();
609 : 0 : return CU_get_error();
610 : : }
611 : :
612 : 4 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
613 : 4 : CU_cleanup_registry();
614 : 4 : return num_failures;
615 : 1 : }
|