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 [ + + # # ]: 2583 : SPDK_LOG_DEPRECATION_REGISTER(nvme_accel_fn_submit_crc,
11 : : "spdk_nvme_accel_fn_table.submit_accel_crc32c", "v25.01", 0);
12 : :
13 : : struct spdk_nvme_poll_group *
14 : 2375 : spdk_nvme_poll_group_create(void *ctx, struct spdk_nvme_accel_fn_table *table)
15 : : {
16 : : struct spdk_nvme_poll_group *group;
17 : :
18 : 2375 : group = calloc(1, sizeof(*group));
19 [ + + ]: 2375 : if (group == NULL) {
20 : 3 : return NULL;
21 : : }
22 : :
23 [ + - + - : 2372 : group->accel_fn_table.table_size = sizeof(struct spdk_nvme_accel_fn_table);
+ - ]
24 [ + + + - : 2372 : if (table && table->table_size != 0) {
+ - - + ]
25 [ + - + - : 2096 : group->accel_fn_table.table_size = table->table_size;
+ - + - +
- ]
26 : : #define SET_FIELD(field) \
27 : : if (offsetof(struct spdk_nvme_accel_fn_table, field) + sizeof(table->field) <= table->table_size) { \
28 : : group->accel_fn_table.field = table->field; \
29 : : } \
30 : :
31 [ + - + - : 2096 : SET_FIELD(submit_accel_crc32c);
- + + - +
- + - + -
+ - ]
32 [ + - + - : 2096 : SET_FIELD(append_crc32c);
- + + - +
- + - + -
+ - ]
33 [ + - + - : 2096 : SET_FIELD(append_copy);
- + + - +
- + - + -
+ - ]
34 [ + - + - : 2096 : SET_FIELD(finish_sequence);
- + + - +
- + - + -
+ - ]
35 [ + - + - : 2096 : SET_FIELD(reverse_sequence);
- + + - +
- + - + -
+ - ]
36 [ + - + - : 2096 : SET_FIELD(abort_sequence);
- + + - +
- + - + -
+ - ]
37 : : /* Do not remove this statement, you should always update this statement when you adding a new field,
38 : : * and do not forget to add the SET_FIELD statement for your added field. */
39 : : SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_accel_fn_table) == 56, "Incorrect size");
40 : :
41 : : #undef SET_FIELD
42 : 1 : }
43 : :
44 : : /* Make sure either all or none of the sequence manipulation callbacks are implemented */
45 [ + + + - : 4469 : if ((group->accel_fn_table.finish_sequence && group->accel_fn_table.reverse_sequence &&
+ - + - +
- + - + -
- + - + ]
46 [ + - + + : 4468 : group->accel_fn_table.abort_sequence) !=
+ - ]
47 [ + + + - : 2648 : (group->accel_fn_table.finish_sequence || group->accel_fn_table.reverse_sequence ||
+ - - + #
# # # # #
# # ]
48 [ - + # # : 276 : group->accel_fn_table.abort_sequence)) {
# # ]
49 : 0 : SPDK_ERRLOG("Invalid accel_fn_table configuration: either all or none of the "
50 : : "sequence callbacks must be provided\n");
51 : 0 : free(group);
52 : 0 : return NULL;
53 : : }
54 : :
55 : : /* Make sure that sequence callbacks are implemented if append* callbacks are provided */
56 [ + + + + : 2373 : if ((group->accel_fn_table.append_crc32c || group->accel_fn_table.append_copy) &&
+ - - + #
# # # # #
+ - ]
57 [ + + + - : 2096 : !group->accel_fn_table.finish_sequence) {
+ - ]
58 : 0 : SPDK_ERRLOG("Invalid accel_fn_table configuration: append_crc32c and/or append_copy require sequence "
59 : : "callbacks to be provided\n");
60 : 0 : free(group);
61 : 0 : return NULL;
62 : : }
63 : :
64 [ + + + - : 2372 : if (group->accel_fn_table.submit_accel_crc32c != NULL) {
+ - + - ]
65 : 0 : SPDK_LOG_DEPRECATED(nvme_accel_fn_submit_crc);
66 : 0 : }
67 : :
68 [ + - + - ]: 2372 : group->ctx = ctx;
69 [ + - + - : 2372 : STAILQ_INIT(&group->tgroups);
+ - + - +
- + - + -
+ - ]
70 : :
71 : 2372 : return group;
72 : 1 : }
73 : :
74 : : struct spdk_nvme_poll_group *
75 : 0 : spdk_nvme_qpair_get_optimal_poll_group(struct spdk_nvme_qpair *qpair)
76 : : {
77 : : struct spdk_nvme_transport_poll_group *tgroup;
78 : :
79 [ # # # # ]: 0 : tgroup = nvme_transport_qpair_get_optimal_poll_group(qpair->transport, qpair);
80 : :
81 [ # # ]: 0 : if (tgroup == NULL) {
82 : 0 : return NULL;
83 : : }
84 : :
85 [ # # # # ]: 0 : return tgroup->group;
86 : 0 : }
87 : :
88 : : int
89 : 2675 : spdk_nvme_poll_group_add(struct spdk_nvme_poll_group *group, struct spdk_nvme_qpair *qpair)
90 : : {
91 : : struct spdk_nvme_transport_poll_group *tgroup;
92 : : const struct spdk_nvme_transport *transport;
93 : :
94 [ + + ]: 2675 : if (nvme_qpair_get_state(qpair) != NVME_QPAIR_DISCONNECTED) {
95 : 3 : return -EINVAL;
96 : : }
97 : :
98 [ + + + - : 2702 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
+ - + - #
# # # #
# ]
99 [ + + # # : 330 : if (tgroup->transport == qpair->transport) {
# # # # #
# ]
100 : 300 : break;
101 : : }
102 : 0 : }
103 : :
104 : : /* See if a new transport has been added (dlopen style) and we need to update the poll group */
105 [ + + ]: 2672 : if (!tgroup) {
106 : 2372 : transport = nvme_get_first_transport();
107 [ + + ]: 3759 : while (transport != NULL) {
108 [ + + + - : 3753 : if (transport == qpair->transport) {
- + ]
109 : 2366 : tgroup = nvme_transport_poll_group_create(transport);
110 [ + + ]: 2366 : if (tgroup == NULL) {
111 : 0 : return -ENOMEM;
112 : : }
113 [ + - + - ]: 2366 : tgroup->group = group;
114 [ + - + - : 2366 : STAILQ_INSERT_TAIL(&group->tgroups, tgroup, link);
+ - + - +
- + - + -
+ - + - +
- + - +
- ]
115 : 2366 : break;
116 : : }
117 : 1387 : transport = nvme_get_next_transport(transport);
118 : : }
119 : 1 : }
120 : :
121 [ + + ]: 2672 : return tgroup ? nvme_transport_poll_group_add(tgroup, qpair) : -ENODEV;
122 : 1 : }
123 : :
124 : : int
125 : 2666 : spdk_nvme_poll_group_remove(struct spdk_nvme_poll_group *group, struct spdk_nvme_qpair *qpair)
126 : : {
127 : : struct spdk_nvme_transport_poll_group *tgroup;
128 : :
129 [ + + + - : 2690 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
+ - + - #
# # # #
# ]
130 [ + + + - : 2687 : if (tgroup->transport == qpair->transport) {
+ - + - -
+ ]
131 : 2663 : return nvme_transport_poll_group_remove(tgroup, qpair);
132 : : }
133 : 0 : }
134 : :
135 : 3 : return -ENODEV;
136 : 1 : }
137 : :
138 : : int
139 : 3699 : nvme_poll_group_connect_qpair(struct spdk_nvme_qpair *qpair)
140 : : {
141 : 3699 : return nvme_transport_poll_group_connect_qpair(qpair);
142 : : }
143 : :
144 : : int
145 : 2645 : nvme_poll_group_disconnect_qpair(struct spdk_nvme_qpair *qpair)
146 : : {
147 : 2645 : return nvme_transport_poll_group_disconnect_qpair(qpair);
148 : : }
149 : :
150 : : int64_t
151 : 1437219521 : spdk_nvme_poll_group_process_completions(struct spdk_nvme_poll_group *group,
152 : : uint32_t completions_per_qpair, spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb)
153 : : {
154 : : struct spdk_nvme_transport_poll_group *tgroup;
155 : 1437219521 : int64_t local_completions = 0, error_reason = 0, num_completions = 0;
156 : :
157 [ + + ]: 1437219521 : if (disconnected_qpair_cb == NULL) {
158 : 0 : return -EINVAL;
159 : : }
160 : :
161 [ + + + + : 1437219521 : if (spdk_unlikely(group->in_process_completions)) {
+ - - + ]
162 : 954013 : return 0;
163 : : }
164 [ + - + - ]: 1436265508 : group->in_process_completions = true;
165 : :
166 [ + + + - : 2872531013 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
+ - + + +
- + - +
- ]
167 : 1436265576 : local_completions = nvme_transport_poll_group_process_completions(tgroup, completions_per_qpair,
168 : 71 : disconnected_qpair_cb);
169 [ + + + - ]: 1436265505 : if (local_completions < 0 && error_reason == 0) {
170 : 30 : error_reason = local_completions;
171 : 0 : } else {
172 [ + - ]: 1436265475 : num_completions += local_completions;
173 : : /* Just to be safe */
174 [ + + # # ]: 1436265475 : assert(num_completions >= 0);
175 : : }
176 : 71 : }
177 [ + - + - ]: 1436265508 : group->in_process_completions = false;
178 : :
179 [ + + ]: 1436265508 : return error_reason ? error_reason : num_completions;
180 : 71 : }
181 : :
182 : : int
183 : 572391 : spdk_nvme_poll_group_all_connected(struct spdk_nvme_poll_group *group)
184 : : {
185 : : struct spdk_nvme_transport_poll_group *tgroup;
186 : : struct spdk_nvme_qpair *qpair;
187 : 572391 : int rc = 0;
188 : :
189 [ + + # # : 1144782 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
# # # # #
# # # #
# ]
190 [ - + # # : 572391 : if (!STAILQ_EMPTY(&tgroup->disconnected_qpairs)) {
# # # # ]
191 : : /* Treat disconnected qpairs as highest priority for notification.
192 : : * This means we can just return immediately here.
193 : : */
194 : 0 : return -EIO;
195 : : }
196 [ + + # # : 574006 : STAILQ_FOREACH(qpair, &tgroup->connected_qpairs, poll_group_stailq) {
# # # # #
# # # #
# ]
197 [ - + ]: 573751 : if (nvme_qpair_get_state(qpair) < NVME_QPAIR_CONNECTING) {
198 : 0 : return -EIO;
199 [ + + ]: 573751 : } else if (nvme_qpair_get_state(qpair) == NVME_QPAIR_CONNECTING) {
200 : 572136 : rc = -EAGAIN;
201 : : /* Break so that we can check the remaining transport groups,
202 : : * in case any of them have a disconnected qpair.
203 : : */
204 : 572136 : break;
205 : : }
206 : 0 : }
207 : 0 : }
208 : :
209 : 572391 : return rc;
210 : 0 : }
211 : :
212 : : void *
213 : 0 : spdk_nvme_poll_group_get_ctx(struct spdk_nvme_poll_group *group)
214 : : {
215 [ # # # # ]: 0 : return group->ctx;
216 : : }
217 : :
218 : : int
219 : 2375 : spdk_nvme_poll_group_destroy(struct spdk_nvme_poll_group *group)
220 : : {
221 : : struct spdk_nvme_transport_poll_group *tgroup, *tmp_tgroup;
222 : :
223 [ + + + - : 4729 : STAILQ_FOREACH_SAFE(tgroup, &group->tgroups, link, tmp_tgroup) {
+ - + + +
- + - + -
+ + ]
224 [ + - + - : 2357 : STAILQ_REMOVE(&group->tgroups, tgroup, spdk_nvme_transport_poll_group, link);
+ - - + +
- + - + -
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
225 [ + + ]: 2357 : if (nvme_transport_poll_group_destroy(tgroup) != 0) {
226 [ # # # # : 3 : STAILQ_INSERT_TAIL(&group->tgroups, tgroup, link);
# # # # #
# # # # #
# # # # #
# # # #
# ]
227 : 3 : return -EBUSY;
228 : : }
229 : :
230 : 1 : }
231 : :
232 : 2372 : free(group);
233 : :
234 : 2372 : return 0;
235 : 1 : }
236 : :
237 : : int
238 : 14 : spdk_nvme_poll_group_get_stats(struct spdk_nvme_poll_group *group,
239 : : struct spdk_nvme_poll_group_stat **stats)
240 : : {
241 : : struct spdk_nvme_transport_poll_group *tgroup;
242 : : struct spdk_nvme_poll_group_stat *result;
243 : 14 : uint32_t transports_count = 0;
244 : : /* Not all transports used by this poll group may support statistics reporting */
245 : 14 : uint32_t reported_stats_count = 0;
246 : : int rc;
247 : :
248 [ - + # # ]: 14 : assert(group);
249 [ - + # # ]: 14 : assert(stats);
250 : :
251 : 14 : result = calloc(1, sizeof(*result));
252 [ - + ]: 14 : if (!result) {
253 : 0 : SPDK_ERRLOG("Failed to allocate memory for poll group statistics\n");
254 : 0 : return -ENOMEM;
255 : : }
256 : :
257 [ + + # # : 31 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
# # # # #
# # # #
# ]
258 : 17 : transports_count++;
259 : 0 : }
260 : :
261 [ # # # # ]: 14 : result->transport_stat = calloc(transports_count, sizeof(*result->transport_stat));
262 [ - + # # : 14 : if (!result->transport_stat) {
# # ]
263 : 0 : SPDK_ERRLOG("Failed to allocate memory for poll group statistics\n");
264 : 0 : free(result);
265 : 0 : return -ENOMEM;
266 : : }
267 : :
268 [ + + # # : 31 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
# # # # #
# # # #
# ]
269 [ # # # # : 17 : rc = nvme_transport_poll_group_get_stats(tgroup, &result->transport_stat[reported_stats_count]);
# # ]
270 [ + - ]: 17 : if (rc == 0) {
271 : 17 : reported_stats_count++;
272 : 0 : }
273 : 0 : }
274 : :
275 [ + + ]: 14 : if (reported_stats_count == 0) {
276 [ # # # # ]: 3 : free(result->transport_stat);
277 : 3 : free(result);
278 [ - + - + : 3 : SPDK_DEBUGLOG(nvme, "No transport statistics available\n");
# # ]
279 : 3 : return -ENOTSUP;
280 : : }
281 : :
282 [ # # # # ]: 11 : result->num_transports = reported_stats_count;
283 [ # # ]: 11 : *stats = result;
284 : :
285 : 11 : return 0;
286 : 0 : }
287 : :
288 : : void
289 : 11 : spdk_nvme_poll_group_free_stats(struct spdk_nvme_poll_group *group,
290 : : struct spdk_nvme_poll_group_stat *stat)
291 : : {
292 : : struct spdk_nvme_transport_poll_group *tgroup;
293 : : uint32_t i;
294 : 11 : uint32_t freed_stats __attribute__((unused)) = 0;
295 : :
296 [ - + # # ]: 11 : assert(group);
297 [ - + # # ]: 11 : assert(stat);
298 : :
299 [ + + # # : 28 : for (i = 0; i < stat->num_transports; i++) {
# # ]
300 [ + - # # : 17 : STAILQ_FOREACH(tgroup, &group->tgroups, link) {
# # # # #
# # # #
# ]
301 [ + - # # : 17 : if (nvme_transport_get_trtype(tgroup->transport) == stat->transport_stat[i]->trtype) {
# # # # #
# # # # #
# # # # ]
302 [ # # # # : 17 : nvme_transport_poll_group_free_stats(tgroup, stat->transport_stat[i]);
# # # # ]
303 : 17 : freed_stats++;
304 : 17 : break;
305 : : }
306 : 0 : }
307 : 0 : }
308 : :
309 [ - + # # : 11 : assert(freed_stats == stat->num_transports);
# # # # ]
310 : :
311 [ # # # # ]: 11 : free(stat->transport_stat);
312 : 11 : free(stat);
313 : 11 : }
|