Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2020 Intel Corporation.
3 : : * Copyright (c) 2021 Mellanox Technologies LTD.
4 : : * Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES.
5 : : * All rights reserved.
6 : : */
7 : :
8 : : #include "nvme_internal.h"
9 : :
10 : : struct spdk_nvme_poll_group *
11 : 2318 : spdk_nvme_poll_group_create(void *ctx, struct spdk_nvme_accel_fn_table *table)
12 : : {
13 : : struct spdk_nvme_poll_group *group;
14 : : int rc;
15 : :
16 : 2318 : group = calloc(1, sizeof(*group));
17 [ + + ]: 2318 : if (group == NULL) {
18 : 4 : return NULL;
19 : : }
20 : :
21 [ + - + - : 2314 : group->accel_fn_table.table_size = sizeof(struct spdk_nvme_accel_fn_table);
+ - ]
22 [ + + + - : 2314 : if (table && table->table_size != 0) {
+ - + - ]
23 [ + - + - : 2051 : group->accel_fn_table.table_size = table->table_size;
+ - + - +
- ]
24 : : #define SET_FIELD(field) \
25 : : if (offsetof(struct spdk_nvme_accel_fn_table, field) + sizeof(table->field) <= table->table_size) { \
26 : : group->accel_fn_table.field = table->field; \
27 : : } \
28 : :
29 [ + + + - : 2051 : SET_FIELD(append_crc32c);
- + + - +
- + - + -
+ - ]
30 [ + + + - : 2051 : SET_FIELD(append_copy);
- + + - +
- + - + -
+ - ]
31 [ + + + - : 2051 : SET_FIELD(finish_sequence);
- + + - +
- + - + -
+ - ]
32 [ + + + - : 2051 : SET_FIELD(reverse_sequence);
- + + - +
- + - + -
+ - ]
33 [ + + + - : 2051 : SET_FIELD(abort_sequence);
- + + - +
- + - + -
+ - ]
34 : : /* Do not remove this statement, you should always update this statement when you adding a new field,
35 : : * and do not forget to add the SET_FIELD statement for your added field. */
36 : : SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_accel_fn_table) == 56, "Incorrect size");
37 : :
38 : : #undef SET_FIELD
39 : 21 : }
40 : :
41 : : /* Make sure either all or none of the sequence manipulation callbacks are implemented */
42 [ + + + - : 4356 : if ((group->accel_fn_table.finish_sequence && group->accel_fn_table.reverse_sequence &&
+ + + - +
- + - + -
+ - - + ]
43 [ + - + + : 4365 : group->accel_fn_table.abort_sequence) !=
+ - ]
44 [ + + + + : 2567 : (group->accel_fn_table.finish_sequence || group->accel_fn_table.reverse_sequence ||
+ - - + #
# # # # #
# # ]
45 [ - + # # : 263 : group->accel_fn_table.abort_sequence)) {
# # ]
46 : 0 : SPDK_ERRLOG("Invalid accel_fn_table configuration: either all or none of the "
47 : : "sequence callbacks must be provided\n");
48 : 0 : free(group);
49 : 0 : return NULL;
50 : : }
51 : :
52 : : /* Make sure that sequence callbacks are implemented if append* callbacks are provided */
53 [ + + + + : 2315 : if ((group->accel_fn_table.append_crc32c || group->accel_fn_table.append_copy) &&
+ - - + #
# # # # #
+ - ]
54 [ + + + - : 2061 : !group->accel_fn_table.finish_sequence) {
+ - ]
55 : 0 : SPDK_ERRLOG("Invalid accel_fn_table configuration: append_crc32c and/or append_copy require sequence "
56 : : "callbacks to be provided\n");
57 : 0 : free(group);
58 : 0 : return NULL;
59 : : }
60 : :
61 : : /* If interrupt is enabled, this fd_group will be used to manage events triggerd on file
62 : : * descriptors of all the qpairs in this poll group */
63 [ + - ]: 2314 : rc = spdk_fd_group_create(&group->fgrp);
64 [ + + ]: 2314 : if (rc) {
65 : : /* Ignore this for non-Linux platforms, as fd_groups aren't supported there. */
66 : : #if defined(__linux__)
67 : 0 : SPDK_ERRLOG("Cannot create fd group for the nvme poll group\n");
68 : 0 : free(group);
69 : 0 : return NULL;
70 : : #endif
71 : 30 : }
72 : :
73 [ - + - + ]: 2314 : group->disconnect_qpair_fd = -1;
74 [ - + - + ]: 2314 : group->ctx = ctx;
75 [ - + - + : 2314 : STAILQ_INIT(&group->tgroups);
- + - + -
+ - + - +
- + ]
76 : :
77 : 2314 : return group;
78 : 32 : }
79 : :
80 : : int
81 : 2 : spdk_nvme_poll_group_get_fd(struct spdk_nvme_poll_group *group)
82 : : {
83 [ - + # # : 2 : if (!group->fgrp) {
# # ]
84 : 0 : SPDK_ERRLOG("No fd group present for the nvme poll group.\n");
85 [ # # ]: 0 : assert(false);
86 : : return -EINVAL;
87 : : }
88 : :
89 [ # # # # ]: 2 : return spdk_fd_group_get_fd(group->fgrp);
90 : : }
91 : :
92 : : struct spdk_fd_group *
93 : 0 : spdk_nvme_poll_group_get_fd_group(struct spdk_nvme_poll_group *group)
94 : : {
95 [ # # # # ]: 0 : return group->fgrp;
96 : : }
97 : :
98 : : struct spdk_nvme_poll_group *
99 : 0 : spdk_nvme_qpair_get_optimal_poll_group(struct spdk_nvme_qpair *qpair)
100 : : {
101 : : struct spdk_nvme_transport_poll_group *tgroup;
102 : :
103 [ # # # # ]: 0 : tgroup = nvme_transport_qpair_get_optimal_poll_group(qpair->transport, qpair);
104 : :
105 [ # # ]: 0 : if (tgroup == NULL) {
106 : 0 : return NULL;
107 : : }
108 : :
109 [ # # # # ]: 0 : return tgroup->group;
110 : 0 : }
111 : :
112 : : #ifdef __linux__
113 : : static int
114 : 2 : nvme_poll_group_read_disconnect_qpair_fd(void *arg)
115 : : {
116 : 2 : return 0;
117 : : }
118 : :
119 : : void
120 : 2438 : nvme_poll_group_write_disconnect_qpair_fd(struct spdk_nvme_poll_group *group)
121 : : {
122 : 2438 : uint64_t notify = 1;
123 : : int rc;
124 : :
125 [ + + + + : 2438 : if (!group->enable_interrupts) {
+ - - + ]
126 : 2436 : return;
127 : : }
128 : :
129 : : /* Write to the disconnect qpair fd. This will generate event on the epoll fd of poll
130 : : * group. We then check for disconnected qpairs in spdk_nvme_poll_group_wait() */
131 [ # # # # ]: 2 : rc = write(group->disconnect_qpair_fd, ¬ify, sizeof(notify));
132 [ - + ]: 2 : if (rc < 0) {
133 [ # # ]: 0 : SPDK_ERRLOG("failed to write the disconnect qpair fd: %s.\n", strerror(errno));
134 : 0 : }
135 : 1 : }
136 : :
137 : : static int
138 : 2 : nvme_poll_group_add_disconnect_qpair_fd(struct spdk_nvme_poll_group *group)
139 : : {
140 : 2 : struct spdk_event_handler_opts opts = {};
141 : : int fd;
142 : :
143 : 2 : fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
144 [ - + ]: 2 : if (fd < 0) {
145 : 0 : return fd;
146 : : }
147 : :
148 [ - + # # : 2 : assert(group->disconnect_qpair_fd == -1);
# # # # ]
149 [ # # # # ]: 2 : group->disconnect_qpair_fd = fd;
150 : :
151 : 2 : spdk_fd_group_get_default_event_handler_opts(&opts, sizeof(opts));
152 [ # # ]: 2 : opts.fd_type = SPDK_FD_TYPE_EVENTFD;
153 : :
154 [ # # # # ]: 2 : return SPDK_FD_GROUP_ADD_EXT(group->fgrp, fd, nvme_poll_group_read_disconnect_qpair_fd,
155 : : group, &opts);
156 : 0 : }
157 : :
158 : : #else
159 : :
160 : : void
161 : 23 : nvme_poll_group_write_disconnect_qpair_fd(struct spdk_nvme_poll_group *group)
162 : : {
163 : 23 : }
164 : :
165 : : static int
166 : 0 : nvme_poll_group_add_disconnect_qpair_fd(struct spdk_nvme_poll_group *group)
167 : : {
168 : 0 : return -ENOTSUP;
169 : : }
170 : :
171 : : #endif
172 : :
173 : : int
174 : 2616 : spdk_nvme_poll_group_add(struct spdk_nvme_poll_group *group, struct spdk_nvme_qpair *qpair)
175 : : {
176 : : struct spdk_nvme_transport_poll_group *tgroup;
177 : : const struct spdk_nvme_transport *transport;
178 : : int rc;
179 : :
180 [ + + ]: 2616 : if (nvme_qpair_get_state(qpair) != NVME_QPAIR_DISCONNECTED) {
181 : 4 : return -EINVAL;
182 : : }
183 : :
184 [ + + + + : 2612 : if (!group->enable_interrupts_is_valid) {
+ - - + ]
185 [ + - + - ]: 2298 : group->enable_interrupts_is_valid = true;
186 [ + + + - : 2298 : group->enable_interrupts = qpair->ctrlr->opts.enable_interrupts;
+ - + - +
- + - + -
+ - ]
187 [ + + + + : 2298 : if (group->enable_interrupts) {
+ - + - ]
188 : 2 : rc = nvme_poll_group_add_disconnect_qpair_fd(group);
189 [ - + ]: 2 : if (rc != 0) {
190 : 0 : return rc;
191 : : }
192 : 0 : }
193 [ + + - + : 341 : } else if (qpair->ctrlr->opts.enable_interrupts != group->enable_interrupts) {
+ + # # #
# # # # #
# # # # #
# ]
194 [ + + + - : 4 : SPDK_ERRLOG("Queue pair %s interrupts cannot be added to poll group\n",
# # # # #
# # # ]
195 : : qpair->ctrlr->opts.enable_interrupts ? "without" : "with");
196 : 4 : return -EINVAL;
197 : : }
198 : :
199 [ + + + - : 2648 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
+ - + - #
# # # #
# ]
200 [ + + # # : 334 : if (tgroup->transport == qpair->transport) {
# # # # #
# ]
201 : 294 : break;
202 : : }
203 : 10 : }
204 : :
205 : : /* See if a new transport has been added (dlopen style) and we need to update the poll group */
206 [ + + ]: 2608 : if (!tgroup) {
207 : 2314 : transport = nvme_get_first_transport();
208 [ + + ]: 3727 : while (transport != NULL) {
209 [ + + + - : 3719 : if (transport == qpair->transport) {
- + ]
210 : 2306 : tgroup = nvme_transport_poll_group_create(transport);
211 [ + + ]: 2306 : if (tgroup == NULL) {
212 : 0 : return -ENOMEM;
213 : : }
214 [ - + - + ]: 2306 : tgroup->group = group;
215 [ - + - + : 2306 : STAILQ_INSERT_TAIL(&group->tgroups, tgroup, link);
- + - + -
+ - + - +
- + - + -
+ - + -
+ ]
216 : 2306 : break;
217 : : }
218 : 1413 : transport = nvme_get_next_transport(transport);
219 : : }
220 : 31 : }
221 : :
222 [ + + ]: 2608 : return tgroup ? nvme_transport_poll_group_add(tgroup, qpair) : -ENODEV;
223 : 37 : }
224 : :
225 : : int
226 : 2600 : spdk_nvme_poll_group_remove(struct spdk_nvme_poll_group *group, struct spdk_nvme_qpair *qpair)
227 : : {
228 : : struct spdk_nvme_transport_poll_group *tgroup;
229 : :
230 [ + + + - : 2632 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
+ - + - #
# # # #
# ]
231 [ + + + - : 2628 : if (tgroup->transport == qpair->transport) {
+ - + - -
+ ]
232 : 2596 : return nvme_transport_poll_group_remove(tgroup, qpair);
233 : : }
234 : 8 : }
235 : :
236 : 4 : return -ENODEV;
237 : 33 : }
238 : :
239 : : static int
240 : 150775 : nvme_qpair_process_completion_wrapper(void *arg)
241 : : {
242 : 150775 : struct spdk_nvme_qpair *qpair = arg;
243 : :
244 : 150775 : return spdk_nvme_qpair_process_completions(qpair, 0);
245 : : }
246 : :
247 : : static int
248 : 3611 : nvme_poll_group_add_qpair_fd(struct spdk_nvme_qpair *qpair)
249 : : {
250 : : struct spdk_nvme_poll_group *group;
251 : 3611 : struct spdk_event_handler_opts opts = {
252 : : .opts_size = SPDK_SIZEOF(&opts, fd_type),
253 : : };
254 : : int fd;
255 : :
256 [ + - + - : 3611 : group = qpair->poll_group->group;
+ - + - ]
257 [ + + + + : 3611 : if (group->enable_interrupts == false) {
+ - - + ]
258 : 3609 : return 0;
259 : : }
260 : :
261 : 2 : fd = spdk_nvme_qpair_get_fd(qpair, &opts);
262 [ - + ]: 2 : if (fd < 0) {
263 : 0 : SPDK_ERRLOG("Cannot get fd for the qpair: %d\n", fd);
264 : 0 : return -EINVAL;
265 : : }
266 : :
267 [ # # # # ]: 2 : return SPDK_FD_GROUP_ADD_EXT(group->fgrp, fd, nvme_qpair_process_completion_wrapper,
268 : : qpair, &opts);
269 : 25 : }
270 : :
271 : : static void
272 : 2564 : nvme_poll_group_remove_qpair_fd(struct spdk_nvme_qpair *qpair)
273 : : {
274 : : struct spdk_nvme_poll_group *group;
275 : : int fd;
276 : :
277 [ + - + - : 2564 : group = qpair->poll_group->group;
+ - + - ]
278 [ + + + + : 2564 : if (group->enable_interrupts == false) {
+ - - + ]
279 : 2562 : return;
280 : : }
281 : :
282 : 2 : fd = spdk_nvme_qpair_get_fd(qpair, NULL);
283 [ - + ]: 2 : if (fd < 0) {
284 : 0 : SPDK_ERRLOG("Cannot get fd for the qpair: %d\n", fd);
285 [ # # ]: 0 : assert(false);
286 : : return;
287 : : }
288 : :
289 [ # # # # ]: 2 : spdk_fd_group_remove(group->fgrp, fd);
290 : 24 : }
291 : :
292 : : int
293 : 3611 : nvme_poll_group_connect_qpair(struct spdk_nvme_qpair *qpair)
294 : : {
295 : : int rc;
296 : :
297 : 3611 : rc = nvme_transport_poll_group_connect_qpair(qpair);
298 [ - + ]: 3611 : if (rc != 0) {
299 : 0 : return rc;
300 : : }
301 : :
302 : 3611 : rc = nvme_poll_group_add_qpair_fd(qpair);
303 [ + + ]: 3611 : if (rc != 0) {
304 : 0 : nvme_transport_poll_group_disconnect_qpair(qpair);
305 : 0 : return rc;
306 : : }
307 : :
308 : 3611 : return 0;
309 : 25 : }
310 : :
311 : : int
312 : 2564 : nvme_poll_group_disconnect_qpair(struct spdk_nvme_qpair *qpair)
313 : : {
314 : 2564 : nvme_poll_group_remove_qpair_fd(qpair);
315 : :
316 : 2564 : return nvme_transport_poll_group_disconnect_qpair(qpair);
317 : : }
318 : :
319 : : int
320 : 150777 : spdk_nvme_poll_group_wait(struct spdk_nvme_poll_group *group,
321 : : spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb)
322 : : {
323 : : struct spdk_nvme_transport_poll_group *tgroup;
324 : 150777 : int num_events, timeout = -1;
325 : :
326 [ - + ]: 150777 : if (disconnected_qpair_cb == NULL) {
327 : 0 : return -EINVAL;
328 : : }
329 : :
330 [ + + # # : 301554 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
# # # # #
# # # #
# ]
331 : 150777 : nvme_transport_poll_group_check_disconnected_qpairs(tgroup, disconnected_qpair_cb);
332 : 0 : }
333 : :
334 [ # # # # ]: 150777 : num_events = spdk_fd_group_wait(group->fgrp, timeout);
335 : :
336 : 150777 : return num_events;
337 : 0 : }
338 : :
339 : : int64_t
340 : 666930849 : spdk_nvme_poll_group_process_completions(struct spdk_nvme_poll_group *group,
341 : : uint32_t completions_per_qpair, spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb)
342 : : {
343 : : struct spdk_nvme_transport_poll_group *tgroup;
344 : 666930849 : int64_t local_completions = 0, error_reason = 0, num_completions = 0;
345 : :
346 [ + + ]: 666930849 : if (disconnected_qpair_cb == NULL) {
347 : 0 : return -EINVAL;
348 : : }
349 : :
350 [ + + + + : 666930849 : if (spdk_unlikely(group->in_process_completions)) {
+ - - + ]
351 : 1257518 : return 0;
352 : : }
353 [ + - + - ]: 665673331 : group->in_process_completions = true;
354 : :
355 [ + + + - : 1331346672 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
+ - + + +
- + - +
- ]
356 : 681495459 : local_completions = nvme_transport_poll_group_process_completions(tgroup, completions_per_qpair,
357 : 15822118 : disconnected_qpair_cb);
358 [ + + + - ]: 665673341 : if (local_completions < 0 && error_reason == 0) {
359 : 45 : error_reason = local_completions;
360 : 0 : } else {
361 [ + - ]: 665673296 : num_completions += local_completions;
362 : : /* Just to be safe */
363 [ + + # # ]: 665673296 : assert(num_completions >= 0);
364 : : }
365 : 15822118 : }
366 [ + - + - ]: 665673331 : group->in_process_completions = false;
367 : :
368 [ + + ]: 665673331 : return error_reason ? error_reason : num_completions;
369 : 15822105 : }
370 : :
371 : : int
372 : 356996 : spdk_nvme_poll_group_all_connected(struct spdk_nvme_poll_group *group)
373 : : {
374 : : struct spdk_nvme_transport_poll_group *tgroup;
375 : : struct spdk_nvme_qpair *qpair;
376 : 356996 : int rc = 0;
377 : :
378 [ + + # # : 713992 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
# # # # #
# # # #
# ]
379 [ + + # # : 356996 : if (!STAILQ_EMPTY(&tgroup->disconnected_qpairs)) {
# # # # ]
380 : : /* Treat disconnected qpairs as highest priority for notification.
381 : : * This means we can just return immediately here.
382 : : */
383 : 0 : return -EIO;
384 : : }
385 [ + + # # : 370289 : STAILQ_FOREACH(qpair, &tgroup->connected_qpairs, poll_group_stailq) {
# # # # #
# # # #
# ]
386 [ - + ]: 370058 : if (nvme_qpair_get_state(qpair) < NVME_QPAIR_CONNECTING) {
387 : 0 : return -EIO;
388 [ + + ]: 370058 : } else if (nvme_qpair_get_state(qpair) == NVME_QPAIR_CONNECTING) {
389 : 356765 : rc = -EAGAIN;
390 : : /* Break so that we can check the remaining transport groups,
391 : : * in case any of them have a disconnected qpair.
392 : : */
393 : 356765 : break;
394 : : }
395 : 2 : }
396 : 1073 : }
397 : :
398 : 356996 : return rc;
399 : 1073 : }
400 : :
401 : : void *
402 : 0 : spdk_nvme_poll_group_get_ctx(struct spdk_nvme_poll_group *group)
403 : : {
404 [ # # # # ]: 0 : return group->ctx;
405 : : }
406 : :
407 : : int
408 : 2318 : spdk_nvme_poll_group_destroy(struct spdk_nvme_poll_group *group)
409 : : {
410 : : struct spdk_nvme_transport_poll_group *tgroup, *tmp_tgroup;
411 [ + - + - ]: 2318 : struct spdk_fd_group *fgrp = group->fgrp;
412 : :
413 [ + + + + : 4604 : STAILQ_FOREACH_SAFE(tgroup, &group->tgroups, link, tmp_tgroup) {
+ - + + +
- + - + -
+ + ]
414 [ + + + + : 2290 : STAILQ_REMOVE(&group->tgroups, tgroup, spdk_nvme_transport_poll_group, link);
+ - - + +
- + - + -
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
415 [ + + ]: 2290 : if (nvme_transport_poll_group_destroy(tgroup) != 0) {
416 [ # # # # : 4 : STAILQ_INSERT_TAIL(&group->tgroups, tgroup, link);
# # # # #
# # # # #
# # # # #
# # # #
# ]
417 : 4 : return -EBUSY;
418 : : }
419 : :
420 : 24 : }
421 : :
422 [ + + ]: 2314 : if (fgrp) {
423 [ + + + + : 2284 : if (group->enable_interrupts) {
+ - + - ]
424 [ # # # # ]: 2 : spdk_fd_group_remove(fgrp, group->disconnect_qpair_fd);
425 [ # # # # ]: 2 : close(group->disconnect_qpair_fd);
426 : 0 : }
427 : 2284 : spdk_fd_group_destroy(fgrp);
428 : 1 : }
429 : :
430 : 2314 : free(group);
431 : :
432 : 2314 : return 0;
433 : 32 : }
434 : :
435 : : int
436 : 16 : spdk_nvme_poll_group_get_stats(struct spdk_nvme_poll_group *group,
437 : : struct spdk_nvme_poll_group_stat **stats)
438 : : {
439 : : struct spdk_nvme_transport_poll_group *tgroup;
440 : : struct spdk_nvme_poll_group_stat *result;
441 : 16 : uint32_t transports_count = 0;
442 : : /* Not all transports used by this poll group may support statistics reporting */
443 : 16 : uint32_t reported_stats_count = 0;
444 : : int rc;
445 : :
446 [ + + # # ]: 16 : assert(group);
447 [ - + # # ]: 16 : assert(stats);
448 : :
449 : 16 : result = calloc(1, sizeof(*result));
450 [ + + ]: 16 : if (!result) {
451 : 0 : SPDK_ERRLOG("Failed to allocate memory for poll group statistics\n");
452 : 0 : return -ENOMEM;
453 : : }
454 : :
455 [ + + # # : 36 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
# # # # #
# # # #
# ]
456 : 20 : transports_count++;
457 : 3 : }
458 : :
459 [ # # # # ]: 16 : result->transport_stat = calloc(transports_count, sizeof(*result->transport_stat));
460 [ - + # # : 16 : if (!result->transport_stat) {
# # ]
461 : 0 : SPDK_ERRLOG("Failed to allocate memory for poll group statistics\n");
462 : 0 : free(result);
463 : 0 : return -ENOMEM;
464 : : }
465 : :
466 [ + + # # : 36 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
# # # # #
# # # #
# ]
467 [ # # # # : 20 : rc = nvme_transport_poll_group_get_stats(tgroup, &result->transport_stat[reported_stats_count]);
# # ]
468 [ + + ]: 20 : if (rc == 0) {
469 : 20 : reported_stats_count++;
470 : 3 : }
471 : 3 : }
472 : :
473 [ + + ]: 16 : if (reported_stats_count == 0) {
474 [ # # # # ]: 4 : free(result->transport_stat);
475 : 4 : free(result);
476 [ + + - + : 4 : SPDK_DEBUGLOG(nvme, "No transport statistics available\n");
# # ]
477 : 4 : return -ENOTSUP;
478 : : }
479 : :
480 [ # # # # ]: 12 : result->num_transports = reported_stats_count;
481 [ # # ]: 12 : *stats = result;
482 : :
483 : 12 : return 0;
484 : 2 : }
485 : :
486 : : void
487 : 12 : spdk_nvme_poll_group_free_stats(struct spdk_nvme_poll_group *group,
488 : : struct spdk_nvme_poll_group_stat *stat)
489 : : {
490 : : struct spdk_nvme_transport_poll_group *tgroup;
491 : : uint32_t i;
492 : 12 : uint32_t freed_stats __attribute__((unused)) = 0;
493 : :
494 [ + + # # ]: 12 : assert(group);
495 [ + + # # ]: 12 : assert(stat);
496 : :
497 [ + + # # : 32 : for (i = 0; i < stat->num_transports; i++) {
# # ]
498 [ + + # # : 20 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
# # # # #
# # # #
# ]
499 [ + + # # : 20 : if (nvme_transport_get_trtype(tgroup->transport) == stat->transport_stat[i]->trtype) {
# # # # #
# # # # #
# # # # ]
500 [ # # # # : 20 : nvme_transport_poll_group_free_stats(tgroup, stat->transport_stat[i]);
# # # # ]
501 : 20 : freed_stats++;
502 : 20 : break;
503 : : }
504 : 0 : }
505 : 3 : }
506 : :
507 [ + + # # : 12 : assert(freed_stats == stat->num_transports);
# # # # ]
508 : :
509 [ # # # # ]: 12 : free(stat->transport_stat);
510 : 12 : free(stat);
511 : 12 : }
|