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 : 2449 : 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 : 2449 : group = calloc(1, sizeof(*group));
17 [ + + ]: 2449 : if (group == NULL) {
18 : 3 : return NULL;
19 : : }
20 : :
21 [ + - + - : 2446 : group->accel_fn_table.table_size = sizeof(struct spdk_nvme_accel_fn_table);
+ - ]
22 [ + + + - : 2446 : if (table && table->table_size != 0) {
+ - + - ]
23 [ + - + - : 2170 : 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 [ + - + - : 2170 : SET_FIELD(append_crc32c);
- + + - +
- + - + -
+ - ]
30 [ + - + - : 2170 : SET_FIELD(append_copy);
- + + - +
- + - + -
+ - ]
31 [ + - + - : 2170 : SET_FIELD(finish_sequence);
- + + - +
- + - + -
+ - ]
32 [ + - + - : 2170 : SET_FIELD(reverse_sequence);
- + + - +
- + - + -
+ - ]
33 [ + - + - : 2170 : 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 : 1 : }
40 : :
41 : : /* Make sure either all or none of the sequence manipulation callbacks are implemented */
42 [ + + + - : 4617 : if ((group->accel_fn_table.finish_sequence && group->accel_fn_table.reverse_sequence &&
+ - + - +
- + - + -
+ - - + ]
43 [ + - + + : 4616 : group->accel_fn_table.abort_sequence) !=
+ - ]
44 [ + + + - : 2722 : (group->accel_fn_table.finish_sequence || group->accel_fn_table.reverse_sequence ||
+ - - + #
# # # # #
# # ]
45 [ - + # # : 276 : 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 [ + + + + : 2447 : if ((group->accel_fn_table.append_crc32c || group->accel_fn_table.append_copy) &&
+ - - + #
# # # # #
+ - ]
54 [ + + + - : 2170 : !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 [ + - ]: 2446 : rc = spdk_fd_group_create(&group->fgrp);
64 [ - + ]: 2446 : 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 : : }
72 : :
73 [ - + - + ]: 2446 : group->disconnect_qpair_fd = -1;
74 [ - + - + ]: 2446 : group->ctx = ctx;
75 [ - + - + : 2446 : STAILQ_INIT(&group->tgroups);
- + - + -
+ - + - +
- + ]
76 : :
77 : 2446 : return group;
78 : 1 : }
79 : :
80 : : int
81 : 0 : spdk_nvme_poll_group_get_fd(struct spdk_nvme_poll_group *group)
82 : : {
83 [ # # # # : 0 : 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 [ # # # # ]: 0 : return spdk_fd_group_get_fd(group->fgrp);
90 : : }
91 : :
92 : : struct spdk_fd_group *
93 : 2 : spdk_nvme_poll_group_get_fd_group(struct spdk_nvme_poll_group *group)
94 : : {
95 [ # # # # ]: 2 : return group->fgrp;
96 : : }
97 : :
98 : : int
99 : 2 : spdk_nvme_poll_group_set_interrupt_callback(struct spdk_nvme_poll_group *group,
100 : : spdk_nvme_poll_group_interrupt_cb cb_fn, void *cb_ctx)
101 : : {
102 [ - + - - : 2 : if (group->interrupt.cb_fn != NULL && cb_fn != NULL) {
# # # # #
# ]
103 : 0 : return -EEXIST;
104 : : }
105 : :
106 [ # # # # : 2 : group->interrupt.cb_fn = cb_fn;
# # ]
107 [ # # # # : 2 : group->interrupt.cb_ctx = cb_ctx;
# # ]
108 : :
109 : 2 : return 0;
110 : 0 : }
111 : :
112 : : struct spdk_nvme_poll_group *
113 : 0 : spdk_nvme_qpair_get_optimal_poll_group(struct spdk_nvme_qpair *qpair)
114 : : {
115 : : struct spdk_nvme_transport_poll_group *tgroup;
116 : :
117 [ # # # # ]: 0 : tgroup = nvme_transport_qpair_get_optimal_poll_group(qpair->transport, qpair);
118 : :
119 [ # # ]: 0 : if (tgroup == NULL) {
120 : 0 : return NULL;
121 : : }
122 : :
123 [ # # # # ]: 0 : return tgroup->group;
124 : 0 : }
125 : :
126 : : #ifdef __linux__
127 : : static int
128 : 2 : nvme_poll_group_read_disconnect_qpair_fd(void *arg)
129 : : {
130 : 2 : struct spdk_nvme_poll_group *group = arg;
131 : :
132 [ + - # # : 2 : if (group->interrupt.cb_fn != NULL) {
# # # # ]
133 [ # # # # : 2 : group->interrupt.cb_fn(group, group->interrupt.cb_ctx);
# # # # #
# # # # #
# # ]
134 : 0 : }
135 : :
136 : 2 : return 0;
137 : : }
138 : :
139 : : void
140 : 2600 : nvme_poll_group_write_disconnect_qpair_fd(struct spdk_nvme_poll_group *group)
141 : : {
142 : 2600 : uint64_t notify = 1;
143 : : int rc;
144 : :
145 [ + + + + : 2600 : if (!group->enable_interrupts) {
+ - - + ]
146 : 2598 : return;
147 : : }
148 : :
149 : : /* Write to the disconnect qpair fd. This will generate event on the epoll fd of poll
150 : : * group. We then check for disconnected qpairs either in spdk_nvme_poll_group_wait() or
151 : : * in transport's poll_group_process_completions() callback.
152 : : */
153 [ # # # # ]: 2 : rc = write(group->disconnect_qpair_fd, ¬ify, sizeof(notify));
154 [ - + ]: 2 : if (rc < 0) {
155 [ # # ]: 0 : SPDK_ERRLOG("failed to write the disconnect qpair fd: %s.\n", strerror(errno));
156 : 0 : }
157 : 1 : }
158 : :
159 : : static int
160 : 2 : nvme_poll_group_add_disconnect_qpair_fd(struct spdk_nvme_poll_group *group)
161 : : {
162 : 2 : struct spdk_event_handler_opts opts = {};
163 : : int fd;
164 : :
165 : 2 : fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
166 [ - + ]: 2 : if (fd < 0) {
167 : 0 : return fd;
168 : : }
169 : :
170 [ - + # # : 2 : assert(group->disconnect_qpair_fd == -1);
# # # # ]
171 [ # # # # ]: 2 : group->disconnect_qpair_fd = fd;
172 : :
173 : 2 : spdk_fd_group_get_default_event_handler_opts(&opts, sizeof(opts));
174 [ # # ]: 2 : opts.fd_type = SPDK_FD_TYPE_EVENTFD;
175 : :
176 [ # # # # ]: 2 : return SPDK_FD_GROUP_ADD_EXT(group->fgrp, fd, nvme_poll_group_read_disconnect_qpair_fd,
177 : : group, &opts);
178 : 0 : }
179 : :
180 : : #else
181 : :
182 : : void
183 : : nvme_poll_group_write_disconnect_qpair_fd(struct spdk_nvme_poll_group *group)
184 : : {
185 : : }
186 : :
187 : : static int
188 : : nvme_poll_group_add_disconnect_qpair_fd(struct spdk_nvme_poll_group *group)
189 : : {
190 : : return -ENOTSUP;
191 : : }
192 : :
193 : : #endif
194 : :
195 : : int
196 : 2758 : spdk_nvme_poll_group_add(struct spdk_nvme_poll_group *group, struct spdk_nvme_qpair *qpair)
197 : : {
198 : : struct spdk_nvme_transport_poll_group *tgroup;
199 : : const struct spdk_nvme_transport *transport;
200 : : int rc;
201 : :
202 [ + + ]: 2758 : if (nvme_qpair_get_state(qpair) != NVME_QPAIR_DISCONNECTED) {
203 : 3 : return -EINVAL;
204 : : }
205 : :
206 [ + + + + : 2755 : if (!group->enable_interrupts_is_valid) {
+ - - + ]
207 [ + - + - ]: 2434 : group->enable_interrupts_is_valid = true;
208 [ + + + - : 2434 : group->enable_interrupts = qpair->ctrlr->opts.enable_interrupts;
+ - + - +
- + - + -
+ - ]
209 [ + + + + : 2434 : if (group->enable_interrupts) {
+ - + - ]
210 : 2 : rc = nvme_poll_group_add_disconnect_qpair_fd(group);
211 [ - + ]: 2 : if (rc != 0) {
212 : 0 : return rc;
213 : : }
214 : 0 : }
215 [ + + - + : 322 : } else if (qpair->ctrlr->opts.enable_interrupts != group->enable_interrupts) {
+ + # # #
# # # # #
# # # # #
# ]
216 [ + + + - : 3 : SPDK_ERRLOG("Queue pair %s interrupts cannot be added to poll group\n",
# # # # #
# # # ]
217 : : qpair->ctrlr->opts.enable_interrupts ? "without" : "with");
218 : 3 : return -EINVAL;
219 : : }
220 : :
221 [ + + + - : 2782 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
+ - + - #
# # # #
# ]
222 [ + + # # : 336 : if (tgroup->transport == qpair->transport) {
# # # # #
# ]
223 : 306 : break;
224 : : }
225 : 0 : }
226 : :
227 : : /* See if a new transport has been added (dlopen style) and we need to update the poll group */
228 [ + + ]: 2752 : if (!tgroup) {
229 : 2446 : transport = nvme_get_first_transport();
230 [ + + ]: 3881 : while (transport != NULL) {
231 [ + + + - : 3875 : if (transport == qpair->transport) {
- + ]
232 : 2440 : tgroup = nvme_transport_poll_group_create(transport);
233 [ + + ]: 2440 : if (tgroup == NULL) {
234 : 0 : return -ENOMEM;
235 : : }
236 [ - + - + ]: 2440 : tgroup->group = group;
237 [ - + - + : 2440 : STAILQ_INSERT_TAIL(&group->tgroups, tgroup, link);
- + - + -
+ - + - +
- + - + -
+ - + -
+ ]
238 : 2440 : break;
239 : : }
240 : 1435 : transport = nvme_get_next_transport(transport);
241 : : }
242 : 1 : }
243 : :
244 [ + + ]: 2752 : return tgroup ? nvme_transport_poll_group_add(tgroup, qpair) : -ENODEV;
245 : 1 : }
246 : :
247 : : int
248 : 2746 : spdk_nvme_poll_group_remove(struct spdk_nvme_poll_group *group, struct spdk_nvme_qpair *qpair)
249 : : {
250 : : struct spdk_nvme_transport_poll_group *tgroup;
251 : :
252 [ + + + - : 2770 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
+ - + - #
# # # #
# ]
253 [ + + + - : 2767 : if (tgroup->transport == qpair->transport) {
+ - + - -
+ ]
254 : 2743 : return nvme_transport_poll_group_remove(tgroup, qpair);
255 : : }
256 : 0 : }
257 : :
258 : 3 : return -ENODEV;
259 : 1 : }
260 : :
261 : : static int
262 : 157998 : nvme_qpair_process_completion_wrapper(void *arg)
263 : : {
264 : 157998 : struct spdk_nvme_qpair *qpair = arg;
265 : :
266 : 157998 : return spdk_nvme_qpair_process_completions(qpair, 0);
267 : : }
268 : :
269 : : static int
270 : 3786 : nvme_poll_group_add_qpair_fd(struct spdk_nvme_qpair *qpair)
271 : : {
272 : : struct spdk_nvme_poll_group *group;
273 : 3786 : struct spdk_event_handler_opts opts = {
274 : : .opts_size = SPDK_SIZEOF(&opts, fd_type),
275 : : };
276 : : int fd;
277 : :
278 [ + - + - : 3786 : group = qpair->poll_group->group;
+ - + - ]
279 [ + + + + : 3786 : if (group->enable_interrupts == false) {
+ - - + ]
280 : 3784 : return 0;
281 : : }
282 : :
283 : 2 : fd = spdk_nvme_qpair_get_fd(qpair, &opts);
284 [ - + ]: 2 : if (fd < 0) {
285 : 0 : SPDK_ERRLOG("Cannot get fd for the qpair: %d\n", fd);
286 : 0 : return -EINVAL;
287 : : }
288 : :
289 [ # # # # ]: 2 : return SPDK_FD_GROUP_ADD_EXT(group->fgrp, fd, nvme_qpair_process_completion_wrapper,
290 : : qpair, &opts);
291 : 1 : }
292 : :
293 : : static void
294 : 2719 : nvme_poll_group_remove_qpair_fd(struct spdk_nvme_qpair *qpair)
295 : : {
296 : : struct spdk_nvme_poll_group *group;
297 : : int fd;
298 : :
299 [ + - + - : 2719 : group = qpair->poll_group->group;
+ - + - ]
300 [ + + + + : 2719 : if (group->enable_interrupts == false) {
+ - - + ]
301 : 2717 : return;
302 : : }
303 : :
304 : 2 : fd = spdk_nvme_qpair_get_fd(qpair, NULL);
305 [ - + ]: 2 : if (fd < 0) {
306 : 0 : SPDK_ERRLOG("Cannot get fd for the qpair: %d\n", fd);
307 [ # # ]: 0 : assert(false);
308 : : return;
309 : : }
310 : :
311 [ # # # # ]: 2 : spdk_fd_group_remove(group->fgrp, fd);
312 : 1 : }
313 : :
314 : : int
315 : 3786 : nvme_poll_group_connect_qpair(struct spdk_nvme_qpair *qpair)
316 : : {
317 : : int rc;
318 : :
319 : 3786 : rc = nvme_transport_poll_group_connect_qpair(qpair);
320 [ - + ]: 3786 : if (rc != 0) {
321 : 0 : return rc;
322 : : }
323 : :
324 : 3786 : rc = nvme_poll_group_add_qpair_fd(qpair);
325 [ + + ]: 3786 : if (rc != 0) {
326 : 0 : nvme_transport_poll_group_disconnect_qpair(qpair);
327 : 0 : return rc;
328 : : }
329 : :
330 : 3786 : return 0;
331 : 1 : }
332 : :
333 : : int
334 : 2719 : nvme_poll_group_disconnect_qpair(struct spdk_nvme_qpair *qpair)
335 : : {
336 : 2719 : nvme_poll_group_remove_qpair_fd(qpair);
337 : :
338 : 2719 : return nvme_transport_poll_group_disconnect_qpair(qpair);
339 : : }
340 : :
341 : : int
342 : 0 : spdk_nvme_poll_group_wait(struct spdk_nvme_poll_group *group,
343 : : spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb)
344 : : {
345 : : struct spdk_nvme_transport_poll_group *tgroup;
346 : 0 : int num_events, timeout = -1;
347 : :
348 [ # # ]: 0 : if (disconnected_qpair_cb == NULL) {
349 : 0 : return -EINVAL;
350 : : }
351 : :
352 [ # # # # : 0 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
# # # # #
# # # #
# ]
353 : 0 : nvme_transport_poll_group_check_disconnected_qpairs(tgroup, disconnected_qpair_cb);
354 : 0 : }
355 : :
356 [ # # # # ]: 0 : num_events = spdk_fd_group_wait(group->fgrp, timeout);
357 : :
358 : 0 : return num_events;
359 : 0 : }
360 : :
361 : : int64_t
362 : 1492267338 : spdk_nvme_poll_group_process_completions(struct spdk_nvme_poll_group *group,
363 : : uint32_t completions_per_qpair, spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb)
364 : : {
365 : : struct spdk_nvme_transport_poll_group *tgroup;
366 : 1492267338 : int64_t local_completions = 0, error_reason = 0, num_completions = 0;
367 : :
368 [ + + ]: 1492267338 : if (disconnected_qpair_cb == NULL) {
369 : 0 : return -EINVAL;
370 : : }
371 : :
372 [ + + + + : 1492267338 : if (spdk_unlikely(group->in_process_completions)) {
+ - - + ]
373 : 1298619 : return 0;
374 : : }
375 [ + - + - ]: 1490968719 : group->in_process_completions = true;
376 : :
377 [ + + + - : 2981937435 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
+ - + + +
- + - +
- ]
378 : 1490968793 : local_completions = nvme_transport_poll_group_process_completions(tgroup, completions_per_qpair,
379 : 77 : disconnected_qpair_cb);
380 [ + + + - ]: 1490968716 : if (local_completions < 0 && error_reason == 0) {
381 : 41 : error_reason = local_completions;
382 : 0 : } else {
383 [ + - ]: 1490968675 : num_completions += local_completions;
384 : : /* Just to be safe */
385 [ + + # # ]: 1490968675 : assert(num_completions >= 0);
386 : : }
387 : 77 : }
388 [ + - + - ]: 1490968719 : group->in_process_completions = false;
389 : :
390 [ + + ]: 1490968719 : return error_reason ? error_reason : num_completions;
391 : 77 : }
392 : :
393 : : int
394 : 535118 : spdk_nvme_poll_group_all_connected(struct spdk_nvme_poll_group *group)
395 : : {
396 : : struct spdk_nvme_transport_poll_group *tgroup;
397 : : struct spdk_nvme_qpair *qpair;
398 : 535118 : int rc = 0;
399 : :
400 [ + + # # : 1070236 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
# # # # #
# # # #
# ]
401 [ - + # # : 535118 : if (!STAILQ_EMPTY(&tgroup->disconnected_qpairs)) {
# # # # ]
402 : : /* Treat disconnected qpairs as highest priority for notification.
403 : : * This means we can just return immediately here.
404 : : */
405 : 0 : return -EIO;
406 : : }
407 [ + + # # : 537976 : STAILQ_FOREACH(qpair, &tgroup->connected_qpairs, poll_group_stailq) {
# # # # #
# # # #
# ]
408 [ - + ]: 537724 : if (nvme_qpair_get_state(qpair) < NVME_QPAIR_CONNECTING) {
409 : 0 : return -EIO;
410 [ + + ]: 537724 : } else if (nvme_qpair_get_state(qpair) == NVME_QPAIR_CONNECTING) {
411 : 534866 : rc = -EAGAIN;
412 : : /* Break so that we can check the remaining transport groups,
413 : : * in case any of them have a disconnected qpair.
414 : : */
415 : 534866 : break;
416 : : }
417 : 0 : }
418 : 0 : }
419 : :
420 : 535118 : return rc;
421 : 0 : }
422 : :
423 : : void *
424 : 0 : spdk_nvme_poll_group_get_ctx(struct spdk_nvme_poll_group *group)
425 : : {
426 [ # # # # ]: 0 : return group->ctx;
427 : : }
428 : :
429 : : int
430 : 2449 : spdk_nvme_poll_group_destroy(struct spdk_nvme_poll_group *group)
431 : : {
432 : : struct spdk_nvme_transport_poll_group *tgroup, *tmp_tgroup;
433 [ + - + - ]: 2449 : struct spdk_fd_group *fgrp = group->fgrp;
434 : :
435 [ + + + - : 4874 : STAILQ_FOREACH_SAFE(tgroup, &group->tgroups, link, tmp_tgroup) {
+ - + + +
- + - + -
+ + ]
436 [ + - + - : 2428 : STAILQ_REMOVE(&group->tgroups, tgroup, spdk_nvme_transport_poll_group, link);
+ - - + +
- + - + -
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
437 [ + + ]: 2428 : if (nvme_transport_poll_group_destroy(tgroup) != 0) {
438 [ # # # # : 3 : STAILQ_INSERT_TAIL(&group->tgroups, tgroup, link);
# # # # #
# # # # #
# # # # #
# # # #
# ]
439 : 3 : return -EBUSY;
440 : : }
441 : :
442 : 1 : }
443 : :
444 [ + - ]: 2446 : if (fgrp) {
445 [ + + + + : 2446 : if (group->enable_interrupts) {
+ - + - ]
446 [ # # # # ]: 2 : spdk_fd_group_remove(fgrp, group->disconnect_qpair_fd);
447 [ # # # # ]: 2 : close(group->disconnect_qpair_fd);
448 : 0 : }
449 : 2446 : spdk_fd_group_destroy(fgrp);
450 : 1 : }
451 : :
452 : 2446 : free(group);
453 : :
454 : 2446 : return 0;
455 : 1 : }
456 : :
457 : : int
458 : 14 : spdk_nvme_poll_group_get_stats(struct spdk_nvme_poll_group *group,
459 : : struct spdk_nvme_poll_group_stat **stats)
460 : : {
461 : : struct spdk_nvme_transport_poll_group *tgroup;
462 : : struct spdk_nvme_poll_group_stat *result;
463 : 14 : uint32_t transports_count = 0;
464 : : /* Not all transports used by this poll group may support statistics reporting */
465 : 14 : uint32_t reported_stats_count = 0;
466 : : int rc;
467 : :
468 [ - + # # ]: 14 : assert(group);
469 [ - + # # ]: 14 : assert(stats);
470 : :
471 : 14 : result = calloc(1, sizeof(*result));
472 [ - + ]: 14 : if (!result) {
473 : 0 : SPDK_ERRLOG("Failed to allocate memory for poll group statistics\n");
474 : 0 : return -ENOMEM;
475 : : }
476 : :
477 [ + + # # : 31 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
# # # # #
# # # #
# ]
478 : 17 : transports_count++;
479 : 0 : }
480 : :
481 [ # # # # ]: 14 : result->transport_stat = calloc(transports_count, sizeof(*result->transport_stat));
482 [ - + # # : 14 : if (!result->transport_stat) {
# # ]
483 : 0 : SPDK_ERRLOG("Failed to allocate memory for poll group statistics\n");
484 : 0 : free(result);
485 : 0 : return -ENOMEM;
486 : : }
487 : :
488 [ + + # # : 31 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
# # # # #
# # # #
# ]
489 [ # # # # : 17 : rc = nvme_transport_poll_group_get_stats(tgroup, &result->transport_stat[reported_stats_count]);
# # ]
490 [ + - ]: 17 : if (rc == 0) {
491 : 17 : reported_stats_count++;
492 : 0 : }
493 : 0 : }
494 : :
495 [ + + ]: 14 : if (reported_stats_count == 0) {
496 [ # # # # ]: 3 : free(result->transport_stat);
497 : 3 : free(result);
498 [ - + - + : 3 : SPDK_DEBUGLOG(nvme, "No transport statistics available\n");
# # ]
499 : 3 : return -ENOTSUP;
500 : : }
501 : :
502 [ # # # # ]: 11 : result->num_transports = reported_stats_count;
503 [ # # ]: 11 : *stats = result;
504 : :
505 : 11 : return 0;
506 : 0 : }
507 : :
508 : : void
509 : 11 : spdk_nvme_poll_group_free_stats(struct spdk_nvme_poll_group *group,
510 : : struct spdk_nvme_poll_group_stat *stat)
511 : : {
512 : : struct spdk_nvme_transport_poll_group *tgroup;
513 : : uint32_t i;
514 : 11 : uint32_t freed_stats __attribute__((unused)) = 0;
515 : :
516 [ - + # # ]: 11 : assert(group);
517 [ - + # # ]: 11 : assert(stat);
518 : :
519 [ + + # # : 28 : for (i = 0; i < stat->num_transports; i++) {
# # ]
520 [ + - # # : 17 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
# # # # #
# # # #
# ]
521 [ + - # # : 17 : if (nvme_transport_get_trtype(tgroup->transport) == stat->transport_stat[i]->trtype) {
# # # # #
# # # # #
# # # # ]
522 [ # # # # : 17 : nvme_transport_poll_group_free_stats(tgroup, stat->transport_stat[i]);
# # # # ]
523 : 17 : freed_stats++;
524 : 17 : break;
525 : : }
526 : 0 : }
527 : 0 : }
528 : :
529 [ - + # # : 11 : assert(freed_stats == stat->num_transports);
# # # # ]
530 : :
531 [ # # # # ]: 11 : free(stat->transport_stat);
532 : 11 : free(stat);
533 : 11 : }
|