Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2016 Intel Corporation. All rights reserved.
3 : : * Copyright (c) 2018-2019, 2021 Mellanox Technologies LTD. All rights reserved.
4 : : * Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : : */
6 : :
7 : : #include "spdk/stdinc.h"
8 : :
9 : : #include "nvmf_internal.h"
10 : : #include "transport.h"
11 : :
12 : : #include "spdk/config.h"
13 : : #include "spdk/log.h"
14 : : #include "spdk/nvmf.h"
15 : : #include "spdk/nvmf_transport.h"
16 : : #include "spdk/queue.h"
17 : : #include "spdk/util.h"
18 : : #include "spdk_internal/usdt.h"
19 : :
20 : : #define NVMF_TRANSPORT_DEFAULT_ASSOCIATION_TIMEOUT_IN_MS 120000
21 : :
22 : : struct nvmf_transport_ops_list_element {
23 : : struct spdk_nvmf_transport_ops ops;
24 : : TAILQ_ENTRY(nvmf_transport_ops_list_element) link;
25 : : };
26 : :
27 : : TAILQ_HEAD(nvmf_transport_ops_list, nvmf_transport_ops_list_element)
28 : : g_spdk_nvmf_transport_ops = TAILQ_HEAD_INITIALIZER(g_spdk_nvmf_transport_ops);
29 : :
30 : : static inline const struct spdk_nvmf_transport_ops *
31 : 2575 : nvmf_get_transport_ops(const char *transport_name)
32 : : {
33 : : struct nvmf_transport_ops_list_element *ops;
34 [ + + ]: 3933 : TAILQ_FOREACH(ops, &g_spdk_nvmf_transport_ops, link) {
35 [ + + - + : 1985 : if (strcasecmp(transport_name, ops->ops.name) == 0) {
+ + ]
36 : 627 : return &ops->ops;
37 : : }
38 : : }
39 : 1948 : return NULL;
40 : : }
41 : :
42 : : void
43 : 1938 : spdk_nvmf_transport_register(const struct spdk_nvmf_transport_ops *ops)
44 : : {
45 : : struct nvmf_transport_ops_list_element *new_ops;
46 : :
47 [ - + ]: 1938 : if (nvmf_get_transport_ops(ops->name) != NULL) {
48 : 0 : SPDK_ERRLOG("Double registering nvmf transport type %s.\n", ops->name);
49 : 0 : assert(false);
50 : : return;
51 : : }
52 : :
53 : 1938 : new_ops = calloc(1, sizeof(*new_ops));
54 [ - + ]: 1938 : if (new_ops == NULL) {
55 : 0 : SPDK_ERRLOG("Unable to allocate memory to register new transport type %s.\n", ops->name);
56 : 0 : assert(false);
57 : : return;
58 : : }
59 : :
60 : 1938 : new_ops->ops = *ops;
61 : :
62 : 1938 : TAILQ_INSERT_TAIL(&g_spdk_nvmf_transport_ops, new_ops, link);
63 : : }
64 : :
65 : : const struct spdk_nvmf_transport_opts *
66 : 168 : spdk_nvmf_get_transport_opts(struct spdk_nvmf_transport *transport)
67 : : {
68 : 168 : return &transport->opts;
69 : : }
70 : :
71 : : void
72 : 168 : nvmf_transport_dump_opts(struct spdk_nvmf_transport *transport, struct spdk_json_write_ctx *w,
73 : : bool named)
74 : : {
75 : 168 : const struct spdk_nvmf_transport_opts *opts = spdk_nvmf_get_transport_opts(transport);
76 : :
77 [ + + ]: 168 : named ? spdk_json_write_named_object_begin(w, "params") : spdk_json_write_object_begin(w);
78 : :
79 : 168 : spdk_json_write_named_string(w, "trtype", spdk_nvmf_get_transport_name(transport));
80 : 168 : spdk_json_write_named_uint32(w, "max_queue_depth", opts->max_queue_depth);
81 : 168 : spdk_json_write_named_uint32(w, "max_io_qpairs_per_ctrlr", opts->max_qpairs_per_ctrlr - 1);
82 : 168 : spdk_json_write_named_uint32(w, "in_capsule_data_size", opts->in_capsule_data_size);
83 : 168 : spdk_json_write_named_uint32(w, "max_io_size", opts->max_io_size);
84 : 168 : spdk_json_write_named_uint32(w, "io_unit_size", opts->io_unit_size);
85 : 168 : spdk_json_write_named_uint32(w, "max_aq_depth", opts->max_aq_depth);
86 : 168 : spdk_json_write_named_uint32(w, "num_shared_buffers", opts->num_shared_buffers);
87 : 168 : spdk_json_write_named_uint32(w, "buf_cache_size", opts->buf_cache_size);
88 [ - + ]: 168 : spdk_json_write_named_bool(w, "dif_insert_or_strip", opts->dif_insert_or_strip);
89 [ - + ]: 168 : spdk_json_write_named_bool(w, "zcopy", opts->zcopy);
90 : :
91 [ + + ]: 168 : if (transport->ops->dump_opts) {
92 : 167 : transport->ops->dump_opts(transport, w);
93 : : }
94 : :
95 : 168 : spdk_json_write_named_uint32(w, "abort_timeout_sec", opts->abort_timeout_sec);
96 : 168 : spdk_json_write_named_uint32(w, "ack_timeout", opts->ack_timeout);
97 : 168 : spdk_json_write_named_uint32(w, "data_wr_pool_size", opts->data_wr_pool_size);
98 : 168 : spdk_json_write_object_end(w);
99 : 168 : }
100 : :
101 : : void
102 : 1543 : nvmf_transport_listen_dump_trid(const struct spdk_nvme_transport_id *trid,
103 : : struct spdk_json_write_ctx *w)
104 : : {
105 : 1543 : const char *adrfam = spdk_nvme_transport_id_adrfam_str(trid->adrfam);
106 : :
107 : 1543 : spdk_json_write_named_string(w, "trtype", trid->trstring);
108 [ + - ]: 1543 : spdk_json_write_named_string(w, "adrfam", adrfam ? adrfam : "unknown");
109 : 1543 : spdk_json_write_named_string(w, "traddr", trid->traddr);
110 : 1543 : spdk_json_write_named_string(w, "trsvcid", trid->trsvcid);
111 : 1543 : }
112 : :
113 : : spdk_nvme_transport_type_t
114 : 0 : spdk_nvmf_get_transport_type(struct spdk_nvmf_transport *transport)
115 : : {
116 : 0 : return transport->ops->type;
117 : : }
118 : :
119 : : const char *
120 : 200 : spdk_nvmf_get_transport_name(struct spdk_nvmf_transport *transport)
121 : : {
122 : 200 : return transport->ops->name;
123 : : }
124 : :
125 : : static void
126 : 602 : nvmf_transport_opts_copy(struct spdk_nvmf_transport_opts *opts,
127 : : struct spdk_nvmf_transport_opts *opts_src,
128 : : size_t opts_size)
129 : : {
130 [ - + ]: 602 : assert(opts);
131 [ - + ]: 602 : assert(opts_src);
132 : :
133 : 602 : opts->opts_size = opts_size;
134 : :
135 : : #define SET_FIELD(field) \
136 : : if (offsetof(struct spdk_nvmf_transport_opts, field) + sizeof(opts->field) <= opts_size) { \
137 : : opts->field = opts_src->field; \
138 : : } \
139 : :
140 [ + - ]: 602 : SET_FIELD(max_queue_depth);
141 [ + - ]: 602 : SET_FIELD(max_qpairs_per_ctrlr);
142 [ + - ]: 602 : SET_FIELD(in_capsule_data_size);
143 [ + - ]: 602 : SET_FIELD(max_io_size);
144 [ + - ]: 602 : SET_FIELD(io_unit_size);
145 [ + - ]: 602 : SET_FIELD(max_aq_depth);
146 [ + - ]: 602 : SET_FIELD(buf_cache_size);
147 [ + - ]: 602 : SET_FIELD(num_shared_buffers);
148 [ + - - + ]: 602 : SET_FIELD(dif_insert_or_strip);
149 [ + - ]: 602 : SET_FIELD(abort_timeout_sec);
150 [ + - ]: 602 : SET_FIELD(association_timeout);
151 [ + - ]: 602 : SET_FIELD(transport_specific);
152 [ + - ]: 602 : SET_FIELD(acceptor_poll_rate);
153 [ + - - + ]: 602 : SET_FIELD(zcopy);
154 [ + - ]: 602 : SET_FIELD(ack_timeout);
155 [ + - ]: 602 : SET_FIELD(data_wr_pool_size);
156 : :
157 : : /* Do not remove this statement, you should always update this statement when you adding a new field,
158 : : * and do not forget to add the SET_FIELD statement for your added field. */
159 : : SPDK_STATIC_ASSERT(sizeof(struct spdk_nvmf_transport_opts) == 72, "Incorrect size");
160 : :
161 : : #undef SET_FIELD
162 : : #undef FILED_CHECK
163 : 602 : }
164 : :
165 : : struct nvmf_transport_create_ctx {
166 : : const struct spdk_nvmf_transport_ops *ops;
167 : : struct spdk_nvmf_transport_opts opts;
168 : : void *cb_arg;
169 : : spdk_nvmf_transport_create_done_cb cb_fn;
170 : : };
171 : :
172 : : static bool
173 : 14625554 : nvmf_transport_use_iobuf(struct spdk_nvmf_transport *transport)
174 : : {
175 [ + + + + ]: 14625554 : return transport->opts.num_shared_buffers || transport->opts.buf_cache_size;
176 : : }
177 : :
178 : : static void
179 : 301 : nvmf_transport_create_async_done(void *cb_arg, struct spdk_nvmf_transport *transport)
180 : : {
181 : 301 : struct nvmf_transport_create_ctx *ctx = cb_arg;
182 : : int chars_written;
183 : :
184 [ - + ]: 301 : if (!transport) {
185 : 0 : SPDK_ERRLOG("Failed to create transport.\n");
186 : 0 : goto err;
187 : : }
188 : :
189 [ - + ]: 301 : pthread_mutex_init(&transport->mutex, NULL);
190 : 301 : TAILQ_INIT(&transport->listeners);
191 : 301 : transport->ops = ctx->ops;
192 : 301 : transport->opts = ctx->opts;
193 [ - + ]: 301 : chars_written = snprintf(transport->iobuf_name, MAX_MEMPOOL_NAME_LENGTH, "%s_%s", "nvmf",
194 : 301 : transport->ops->name);
195 [ - + ]: 301 : if (chars_written < 0) {
196 : 0 : SPDK_ERRLOG("Unable to generate transport data buffer pool name.\n");
197 : 0 : goto err;
198 : : }
199 : :
200 [ + + ]: 301 : if (nvmf_transport_use_iobuf(transport)) {
201 : 289 : spdk_iobuf_register_module(transport->iobuf_name);
202 : : }
203 : :
204 : 301 : ctx->cb_fn(ctx->cb_arg, transport);
205 : 301 : free(ctx);
206 : 301 : return;
207 : :
208 : 0 : err:
209 [ # # ]: 0 : if (transport) {
210 : 0 : transport->ops->destroy(transport, NULL, NULL);
211 : : }
212 : :
213 : 0 : ctx->cb_fn(ctx->cb_arg, NULL);
214 : 0 : free(ctx);
215 : : }
216 : :
217 : : static void
218 : 286 : _nvmf_transport_create_done(void *ctx)
219 : : {
220 : 286 : struct nvmf_transport_create_ctx *_ctx = (struct nvmf_transport_create_ctx *)ctx;
221 : :
222 : 286 : nvmf_transport_create_async_done(_ctx, _ctx->ops->create(&_ctx->opts));
223 : 286 : }
224 : :
225 : : static int
226 : 321 : nvmf_transport_create(const char *transport_name, struct spdk_nvmf_transport_opts *opts,
227 : : spdk_nvmf_transport_create_done_cb cb_fn, void *cb_arg, bool sync)
228 : : {
229 : : struct nvmf_transport_create_ctx *ctx;
230 : 321 : struct spdk_iobuf_opts opts_iobuf = {};
231 : : int rc;
232 : : uint64_t count;
233 : :
234 : 321 : ctx = calloc(1, sizeof(*ctx));
235 [ - + ]: 321 : if (!ctx) {
236 : 0 : return -ENOMEM;
237 : : }
238 : :
239 [ - + ]: 321 : if (!opts) {
240 : 0 : SPDK_ERRLOG("opts should not be NULL\n");
241 : 0 : goto err;
242 : : }
243 : :
244 [ - + ]: 321 : if (!opts->opts_size) {
245 : 0 : SPDK_ERRLOG("The opts_size in opts structure should not be zero\n");
246 : 0 : goto err;
247 : : }
248 : :
249 : 321 : ctx->ops = nvmf_get_transport_ops(transport_name);
250 [ + + ]: 321 : if (!ctx->ops) {
251 : 5 : SPDK_ERRLOG("Transport type '%s' unavailable.\n", transport_name);
252 : 5 : goto err;
253 : : }
254 : :
255 : 316 : nvmf_transport_opts_copy(&ctx->opts, opts, opts->opts_size);
256 [ + + + - ]: 316 : if (ctx->opts.max_io_size != 0 && (!spdk_u32_is_pow2(ctx->opts.max_io_size) ||
257 [ + + ]: 311 : ctx->opts.max_io_size < 8192)) {
258 : 5 : SPDK_ERRLOG("max_io_size %u must be a power of 2 and be greater than or equal 8KB\n",
259 : : ctx->opts.max_io_size);
260 : 5 : goto err;
261 : : }
262 : :
263 [ + + ]: 311 : if (ctx->opts.max_aq_depth < SPDK_NVMF_MIN_ADMIN_MAX_SQ_SIZE) {
264 : 5 : SPDK_ERRLOG("max_aq_depth %u is less than minimum defined by NVMf spec, use min value\n",
265 : : ctx->opts.max_aq_depth);
266 : 5 : ctx->opts.max_aq_depth = SPDK_NVMF_MIN_ADMIN_MAX_SQ_SIZE;
267 : : }
268 : :
269 : 311 : spdk_iobuf_get_opts(&opts_iobuf, sizeof(opts_iobuf));
270 [ + + ]: 311 : if (ctx->opts.io_unit_size == 0) {
271 : 5 : SPDK_ERRLOG("io_unit_size cannot be 0\n");
272 : 5 : goto err;
273 : : }
274 [ + + ]: 306 : if (ctx->opts.io_unit_size > opts_iobuf.large_bufsize) {
275 : 5 : SPDK_ERRLOG("io_unit_size %u is larger than iobuf pool large buffer size %d\n",
276 : : ctx->opts.io_unit_size, opts_iobuf.large_bufsize);
277 : 5 : goto err;
278 : : }
279 : :
280 [ + + ]: 301 : if (ctx->opts.io_unit_size <= opts_iobuf.small_bufsize) {
281 : : /* We'll be using the small buffer pool only */
282 : 164 : count = opts_iobuf.small_pool_count;
283 : : } else {
284 : 137 : count = spdk_min(opts_iobuf.small_pool_count, opts_iobuf.large_pool_count);
285 : : }
286 : :
287 [ - + ]: 301 : if (ctx->opts.num_shared_buffers > count) {
288 : 0 : SPDK_WARNLOG("The num_shared_buffers value (%u) is larger than the available iobuf"
289 : : " pool size (%lu). Please increase the iobuf pool sizes.\n",
290 : : ctx->opts.num_shared_buffers, count);
291 : : }
292 : :
293 : 301 : ctx->cb_fn = cb_fn;
294 : 301 : ctx->cb_arg = cb_arg;
295 : :
296 : : /* Prioritize sync create operation. */
297 [ + + ]: 301 : if (ctx->ops->create) {
298 [ + + ]: 286 : if (sync) {
299 : 5 : _nvmf_transport_create_done(ctx);
300 : 5 : return 0;
301 : : }
302 : :
303 : 281 : rc = spdk_thread_send_msg(spdk_get_thread(), _nvmf_transport_create_done, ctx);
304 [ - + ]: 281 : if (rc) {
305 : 0 : goto err;
306 : : }
307 : :
308 : 281 : return 0;
309 : : }
310 : :
311 [ - + ]: 15 : assert(ctx->ops->create_async);
312 : 15 : rc = ctx->ops->create_async(&ctx->opts, nvmf_transport_create_async_done, ctx);
313 [ - + ]: 15 : if (rc) {
314 : 0 : SPDK_ERRLOG("Unable to create new transport of type %s\n", transport_name);
315 : 0 : goto err;
316 : : }
317 : :
318 : 15 : return 0;
319 : 20 : err:
320 : 20 : free(ctx);
321 : 20 : return -1;
322 : : }
323 : :
324 : : int
325 : 316 : spdk_nvmf_transport_create_async(const char *transport_name, struct spdk_nvmf_transport_opts *opts,
326 : : spdk_nvmf_transport_create_done_cb cb_fn, void *cb_arg)
327 : : {
328 : 316 : return nvmf_transport_create(transport_name, opts, cb_fn, cb_arg, false);
329 : : }
330 : :
331 : : static void
332 : 5 : nvmf_transport_create_sync_done(void *cb_arg, struct spdk_nvmf_transport *transport)
333 : : {
334 : 5 : struct spdk_nvmf_transport **_transport = cb_arg;
335 : :
336 : 5 : *_transport = transport;
337 : 5 : }
338 : :
339 : : struct spdk_nvmf_transport *
340 : 5 : spdk_nvmf_transport_create(const char *transport_name, struct spdk_nvmf_transport_opts *opts)
341 : : {
342 : 5 : struct spdk_nvmf_transport *transport = NULL;
343 : :
344 : : /* Current implementation supports synchronous version of create operation only. */
345 [ + - + - ]: 5 : assert(nvmf_get_transport_ops(transport_name) && nvmf_get_transport_ops(transport_name)->create);
346 : :
347 : 5 : nvmf_transport_create(transport_name, opts, nvmf_transport_create_sync_done, &transport, true);
348 : 5 : return transport;
349 : : }
350 : :
351 : : struct spdk_nvmf_transport *
352 : 6454 : spdk_nvmf_transport_get_first(struct spdk_nvmf_tgt *tgt)
353 : : {
354 : 6454 : return TAILQ_FIRST(&tgt->transports);
355 : : }
356 : :
357 : : struct spdk_nvmf_transport *
358 : 6332 : spdk_nvmf_transport_get_next(struct spdk_nvmf_transport *transport)
359 : : {
360 : 6332 : return TAILQ_NEXT(transport, link);
361 : : }
362 : :
363 : : int
364 : 296 : spdk_nvmf_transport_destroy(struct spdk_nvmf_transport *transport,
365 : : spdk_nvmf_transport_destroy_done_cb cb_fn, void *cb_arg)
366 : : {
367 : : struct spdk_nvmf_listener *listener, *listener_tmp;
368 : :
369 [ - + ]: 296 : TAILQ_FOREACH_SAFE(listener, &transport->listeners, link, listener_tmp) {
370 [ # # ]: 0 : TAILQ_REMOVE(&transport->listeners, listener, link);
371 : 0 : transport->ops->stop_listen(transport, &listener->trid);
372 : 0 : free(listener);
373 : : }
374 : :
375 [ + + ]: 296 : if (nvmf_transport_use_iobuf(transport)) {
376 : 289 : spdk_iobuf_unregister_module(transport->iobuf_name);
377 : : }
378 : :
379 [ - + ]: 296 : pthread_mutex_destroy(&transport->mutex);
380 : 296 : return transport->ops->destroy(transport, cb_fn, cb_arg);
381 : : }
382 : :
383 : : struct spdk_nvmf_listener *
384 : 1717 : nvmf_transport_find_listener(struct spdk_nvmf_transport *transport,
385 : : const struct spdk_nvme_transport_id *trid)
386 : : {
387 : : struct spdk_nvmf_listener *listener;
388 : :
389 [ + + ]: 1981 : TAILQ_FOREACH(listener, &transport->listeners, link) {
390 [ + + ]: 1588 : if (spdk_nvme_transport_id_compare(&listener->trid, trid) == 0) {
391 : 1324 : return listener;
392 : : }
393 : : }
394 : :
395 : 393 : return NULL;
396 : : }
397 : :
398 : : int
399 : 569 : spdk_nvmf_transport_listen(struct spdk_nvmf_transport *transport,
400 : : const struct spdk_nvme_transport_id *trid, struct spdk_nvmf_listen_opts *opts)
401 : : {
402 : : struct spdk_nvmf_listener *listener;
403 : : int rc;
404 : :
405 : 569 : listener = nvmf_transport_find_listener(transport, trid);
406 [ + + ]: 569 : if (!listener) {
407 : 378 : listener = calloc(1, sizeof(*listener));
408 [ - + ]: 378 : if (!listener) {
409 : 0 : return -ENOMEM;
410 : : }
411 : :
412 : 378 : listener->ref = 1;
413 : 378 : listener->trid = *trid;
414 : 378 : listener->sock_impl = opts->sock_impl;
415 : 378 : TAILQ_INSERT_TAIL(&transport->listeners, listener, link);
416 [ - + ]: 378 : pthread_mutex_lock(&transport->mutex);
417 : 378 : rc = transport->ops->listen(transport, &listener->trid, opts);
418 [ - + ]: 378 : pthread_mutex_unlock(&transport->mutex);
419 [ + + ]: 378 : if (rc != 0) {
420 [ - + ]: 5 : TAILQ_REMOVE(&transport->listeners, listener, link);
421 : 5 : free(listener);
422 : : }
423 : 378 : return rc;
424 : : }
425 : :
426 [ - + - - : 191 : if (opts->sock_impl && strncmp(opts->sock_impl, listener->sock_impl, strlen(listener->sock_impl))) {
- - - - -
- ]
427 : 0 : SPDK_ERRLOG("opts->sock_impl: '%s' doesn't match listener->sock_impl: '%s'\n", opts->sock_impl,
428 : : listener->sock_impl);
429 : 0 : return -EINVAL;
430 : : }
431 : :
432 : 191 : ++listener->ref;
433 : :
434 : 191 : return 0;
435 : : }
436 : :
437 : : int
438 : 569 : spdk_nvmf_transport_stop_listen(struct spdk_nvmf_transport *transport,
439 : : const struct spdk_nvme_transport_id *trid)
440 : : {
441 : : struct spdk_nvmf_listener *listener;
442 : :
443 : 569 : listener = nvmf_transport_find_listener(transport, trid);
444 [ + + ]: 569 : if (!listener) {
445 : 5 : return -ENOENT;
446 : : }
447 : :
448 [ + + ]: 564 : if (--listener->ref == 0) {
449 [ + + ]: 373 : TAILQ_REMOVE(&transport->listeners, listener, link);
450 [ - + ]: 373 : pthread_mutex_lock(&transport->mutex);
451 : 373 : transport->ops->stop_listen(transport, trid);
452 [ - + ]: 373 : pthread_mutex_unlock(&transport->mutex);
453 : 373 : free(listener);
454 : : }
455 : :
456 : 564 : return 0;
457 : : }
458 : :
459 : : struct nvmf_stop_listen_ctx {
460 : : struct spdk_nvmf_transport *transport;
461 : : struct spdk_nvme_transport_id trid;
462 : : struct spdk_nvmf_subsystem *subsystem;
463 : : spdk_nvmf_tgt_subsystem_listen_done_fn cb_fn;
464 : : void *cb_arg;
465 : : };
466 : :
467 : : static void
468 : 41 : nvmf_stop_listen_fini(struct spdk_io_channel_iter *i, int status)
469 : : {
470 : : struct nvmf_stop_listen_ctx *ctx;
471 : : struct spdk_nvmf_transport *transport;
472 : 41 : int rc = status;
473 : :
474 : 41 : ctx = spdk_io_channel_iter_get_ctx(i);
475 : 41 : transport = ctx->transport;
476 [ - + ]: 41 : assert(transport != NULL);
477 : :
478 : 41 : rc = spdk_nvmf_transport_stop_listen(transport, &ctx->trid);
479 [ - + ]: 41 : if (rc) {
480 : 0 : SPDK_ERRLOG("Failed to stop listening on address '%s'\n", ctx->trid.traddr);
481 : : }
482 : :
483 [ + - ]: 41 : if (ctx->cb_fn) {
484 : 41 : ctx->cb_fn(ctx->cb_arg, rc);
485 : : }
486 : 41 : free(ctx);
487 : 41 : }
488 : :
489 : : static void nvmf_stop_listen_disconnect_qpairs(struct spdk_io_channel_iter *i);
490 : :
491 : : static void
492 : 38 : nvmf_stop_listen_disconnect_qpairs_msg(void *ctx)
493 : : {
494 : 38 : nvmf_stop_listen_disconnect_qpairs((struct spdk_io_channel_iter *)ctx);
495 : 38 : }
496 : :
497 : : static void
498 : 134 : nvmf_stop_listen_disconnect_qpairs(struct spdk_io_channel_iter *i)
499 : : {
500 : : struct nvmf_stop_listen_ctx *ctx;
501 : : struct spdk_nvmf_poll_group *group;
502 : : struct spdk_io_channel *ch;
503 : : struct spdk_nvmf_qpair *qpair, *tmp_qpair;
504 : 19 : struct spdk_nvme_transport_id tmp_trid;
505 : 134 : bool qpair_found = false;
506 : :
507 : 134 : ctx = spdk_io_channel_iter_get_ctx(i);
508 : 134 : ch = spdk_io_channel_iter_get_channel(i);
509 : 134 : group = spdk_io_channel_get_ctx(ch);
510 : :
511 [ + + ]: 222 : TAILQ_FOREACH_SAFE(qpair, &group->qpairs, link, tmp_qpair) {
512 [ - + ]: 88 : if (spdk_nvmf_qpair_get_listen_trid(qpair, &tmp_trid)) {
513 : 0 : continue;
514 : : }
515 : :
516 : : /* Skip qpairs that don't match the listen trid and subsystem pointer. If
517 : : * the ctx->subsystem is NULL, it means disconnect all qpairs that match
518 : : * the listen trid. */
519 [ + + ]: 88 : if (!spdk_nvme_transport_id_compare(&ctx->trid, &tmp_trid)) {
520 [ + - ]: 52 : if (ctx->subsystem == NULL ||
521 [ + - + - ]: 52 : (qpair->ctrlr != NULL && ctx->subsystem == qpair->ctrlr->subsys)) {
522 : 52 : spdk_nvmf_qpair_disconnect(qpair);
523 : 52 : qpair_found = true;
524 : : }
525 : : }
526 : : }
527 [ + + ]: 134 : if (qpair_found) {
528 : 38 : spdk_thread_send_msg(spdk_get_thread(), nvmf_stop_listen_disconnect_qpairs_msg, i);
529 : 38 : return;
530 : : }
531 : :
532 : 96 : spdk_for_each_channel_continue(i, 0);
533 : : }
534 : :
535 : : int
536 : 41 : spdk_nvmf_transport_stop_listen_async(struct spdk_nvmf_transport *transport,
537 : : const struct spdk_nvme_transport_id *trid,
538 : : struct spdk_nvmf_subsystem *subsystem,
539 : : spdk_nvmf_tgt_subsystem_listen_done_fn cb_fn,
540 : : void *cb_arg)
541 : : {
542 : : struct nvmf_stop_listen_ctx *ctx;
543 : :
544 [ - + ]: 41 : if (trid->subnqn[0] != '\0') {
545 : 0 : SPDK_ERRLOG("subnqn should be empty, use subsystem pointer instead\n");
546 : 0 : return -EINVAL;
547 : : }
548 : :
549 : 41 : ctx = calloc(1, sizeof(struct nvmf_stop_listen_ctx));
550 [ - + ]: 41 : if (ctx == NULL) {
551 : 0 : return -ENOMEM;
552 : : }
553 : :
554 : 41 : ctx->trid = *trid;
555 : 41 : ctx->subsystem = subsystem;
556 : 41 : ctx->transport = transport;
557 : 41 : ctx->cb_fn = cb_fn;
558 : 41 : ctx->cb_arg = cb_arg;
559 : :
560 : 41 : spdk_for_each_channel(transport->tgt, nvmf_stop_listen_disconnect_qpairs, ctx,
561 : : nvmf_stop_listen_fini);
562 : :
563 : 41 : return 0;
564 : : }
565 : :
566 : : void
567 : 728 : nvmf_transport_listener_discover(struct spdk_nvmf_transport *transport,
568 : : struct spdk_nvme_transport_id *trid,
569 : : struct spdk_nvmf_discovery_log_page_entry *entry)
570 : : {
571 : 728 : transport->ops->listener_discover(transport, trid, entry);
572 : 728 : }
573 : :
574 : : struct spdk_nvmf_transport_poll_group *
575 : 636 : nvmf_transport_poll_group_create(struct spdk_nvmf_transport *transport,
576 : : struct spdk_nvmf_poll_group *group)
577 : : {
578 : : struct spdk_nvmf_transport_poll_group *tgroup;
579 : 636 : struct spdk_iobuf_opts opts_iobuf = {};
580 : : uint32_t buf_cache_size, small_cache_size, large_cache_size;
581 : : int rc;
582 : :
583 [ - + ]: 636 : pthread_mutex_lock(&transport->mutex);
584 : 636 : tgroup = transport->ops->poll_group_create(transport, group);
585 [ - + ]: 636 : pthread_mutex_unlock(&transport->mutex);
586 [ - + ]: 636 : if (!tgroup) {
587 : 0 : return NULL;
588 : : }
589 : 636 : tgroup->transport = transport;
590 : :
591 : 636 : STAILQ_INIT(&tgroup->pending_buf_queue);
592 : :
593 [ + + ]: 636 : if (!nvmf_transport_use_iobuf(transport)) {
594 : : /* We aren't going to allocate any shared buffers or cache, so just return now. */
595 : 21 : return tgroup;
596 : : }
597 : :
598 : 615 : buf_cache_size = transport->opts.buf_cache_size;
599 : :
600 : : /* buf_cache_size of UINT32_MAX means the value should be calculated dynamically
601 : : * based on the number of buffers in the shared pool and the number of poll groups
602 : : * that are sharing them. We allocate 75% of the pool for the cache, and then
603 : : * divide that by number of poll groups to determine the buf_cache_size for this
604 : : * poll group.
605 : : */
606 [ + + ]: 615 : if (buf_cache_size == UINT32_MAX) {
607 : 602 : uint32_t num_shared_buffers = transport->opts.num_shared_buffers;
608 : :
609 : : /* Theoretically the nvmf library can dynamically add poll groups to
610 : : * the target, after transports have already been created. We aren't
611 : : * going to try to really handle this case efficiently, just do enough
612 : : * here to ensure we don't divide-by-zero.
613 : : */
614 [ + - ]: 602 : uint16_t num_poll_groups = group->tgt->num_poll_groups ? : spdk_env_get_core_count();
615 : :
616 [ - + ]: 602 : buf_cache_size = (num_shared_buffers * 3 / 4) / num_poll_groups;
617 : : }
618 : :
619 : 615 : spdk_iobuf_get_opts(&opts_iobuf, sizeof(opts_iobuf));
620 : 615 : small_cache_size = buf_cache_size;
621 [ + + ]: 615 : if (transport->opts.io_unit_size <= opts_iobuf.small_bufsize) {
622 : 482 : large_cache_size = 0;
623 : : } else {
624 : 133 : large_cache_size = buf_cache_size;
625 : : }
626 : :
627 : 615 : tgroup->buf_cache = calloc(1, sizeof(*tgroup->buf_cache));
628 [ - + ]: 615 : if (!tgroup->buf_cache) {
629 : 0 : SPDK_ERRLOG("Unable to allocate an iobuf channel in the poll group.\n");
630 : 0 : goto err;
631 : : }
632 : :
633 : 615 : rc = spdk_iobuf_channel_init(tgroup->buf_cache, transport->iobuf_name, small_cache_size,
634 : : large_cache_size);
635 [ - + ]: 615 : if (rc != 0) {
636 : 0 : SPDK_ERRLOG("Unable to reserve the full number of buffers for the pg buffer cache.\n");
637 : 0 : rc = spdk_iobuf_channel_init(tgroup->buf_cache, transport->iobuf_name, 0, 0);
638 [ # # ]: 0 : if (rc != 0) {
639 : 0 : SPDK_ERRLOG("Unable to create an iobuf channel in the poll group.\n");
640 : 0 : goto err;
641 : : }
642 : : }
643 : :
644 : 615 : return tgroup;
645 : 0 : err:
646 : 0 : transport->ops->poll_group_destroy(tgroup);
647 : 0 : return NULL;
648 : : }
649 : :
650 : : struct spdk_nvmf_transport_poll_group *
651 : 9893 : nvmf_transport_get_optimal_poll_group(struct spdk_nvmf_transport *transport,
652 : : struct spdk_nvmf_qpair *qpair)
653 : : {
654 : : struct spdk_nvmf_transport_poll_group *tgroup;
655 : :
656 [ + - ]: 9893 : if (transport->ops->get_optimal_poll_group) {
657 [ - + ]: 9893 : pthread_mutex_lock(&transport->mutex);
658 : 9893 : tgroup = transport->ops->get_optimal_poll_group(qpair);
659 [ - + ]: 9893 : pthread_mutex_unlock(&transport->mutex);
660 : :
661 : 9893 : return tgroup;
662 : : } else {
663 : 0 : return NULL;
664 : : }
665 : : }
666 : :
667 : : void
668 : 636 : nvmf_transport_poll_group_destroy(struct spdk_nvmf_transport_poll_group *group)
669 : : {
670 : : struct spdk_nvmf_transport *transport;
671 : 636 : struct spdk_iobuf_channel *ch = NULL;
672 : :
673 : 636 : transport = group->transport;
674 : :
675 [ - + ]: 636 : if (!STAILQ_EMPTY(&group->pending_buf_queue)) {
676 : 0 : SPDK_ERRLOG("Pending I/O list wasn't empty on poll group destruction\n");
677 : : }
678 : :
679 [ + + ]: 636 : if (nvmf_transport_use_iobuf(transport)) {
680 : : /* The call to poll_group_destroy both frees the group memory, but also
681 : : * releases any remaining buffers. Cache channel pointer so we can still
682 : : * release the resources after the group has been freed. */
683 : 615 : ch = group->buf_cache;
684 : : }
685 : :
686 [ - + ]: 636 : pthread_mutex_lock(&transport->mutex);
687 : 636 : transport->ops->poll_group_destroy(group);
688 [ - + ]: 636 : pthread_mutex_unlock(&transport->mutex);
689 : :
690 [ + + ]: 636 : if (nvmf_transport_use_iobuf(transport)) {
691 : 615 : spdk_iobuf_channel_fini(ch);
692 : 615 : free(ch);
693 : : }
694 : 636 : }
695 : :
696 : : int
697 : 9893 : nvmf_transport_poll_group_add(struct spdk_nvmf_transport_poll_group *group,
698 : : struct spdk_nvmf_qpair *qpair)
699 : : {
700 [ + - ]: 9893 : if (qpair->transport) {
701 [ - + ]: 9893 : assert(qpair->transport == group->transport);
702 [ - + ]: 9893 : if (qpair->transport != group->transport) {
703 : 0 : return -1;
704 : : }
705 : : } else {
706 : 0 : qpair->transport = group->transport;
707 : : }
708 : :
709 : 3541 : SPDK_DTRACE_PROBE3(nvmf_transport_poll_group_add, qpair, qpair->qid,
710 : : spdk_thread_get_id(group->group->thread));
711 : :
712 : 9893 : return group->transport->ops->poll_group_add(group, qpair);
713 : : }
714 : :
715 : : int
716 : 9893 : nvmf_transport_poll_group_remove(struct spdk_nvmf_transport_poll_group *group,
717 : : struct spdk_nvmf_qpair *qpair)
718 : : {
719 : 9893 : int rc = ENOTSUP;
720 : :
721 : 3541 : SPDK_DTRACE_PROBE3(nvmf_transport_poll_group_remove, qpair, qpair->qid,
722 : : spdk_thread_get_id(group->group->thread));
723 : :
724 [ - + ]: 9893 : assert(qpair->transport == group->transport);
725 [ + - ]: 9893 : if (group->transport->ops->poll_group_remove) {
726 : 9893 : rc = group->transport->ops->poll_group_remove(group, qpair);
727 : : }
728 : :
729 : 9893 : return rc;
730 : : }
731 : :
732 : : int
733 : 1751162028 : nvmf_transport_poll_group_poll(struct spdk_nvmf_transport_poll_group *group)
734 : : {
735 : 1751162028 : return group->transport->ops->poll_group_poll(group);
736 : : }
737 : :
738 : : int
739 : 5909 : nvmf_transport_req_free(struct spdk_nvmf_request *req)
740 : : {
741 : 5909 : return req->qpair->transport->ops->req_free(req);
742 : : }
743 : :
744 : : int
745 : 25021917 : nvmf_transport_req_complete(struct spdk_nvmf_request *req)
746 : : {
747 : 25021917 : return req->qpair->transport->ops->req_complete(req);
748 : : }
749 : :
750 : : void
751 : 9893 : nvmf_transport_qpair_fini(struct spdk_nvmf_qpair *qpair,
752 : : spdk_nvmf_transport_qpair_fini_cb cb_fn,
753 : : void *cb_arg)
754 : : {
755 : 3541 : SPDK_DTRACE_PROBE1(nvmf_transport_qpair_fini, qpair);
756 : :
757 : 9893 : qpair->transport->ops->qpair_fini(qpair, cb_fn, cb_arg);
758 : 9893 : }
759 : :
760 : : int
761 : 298 : nvmf_transport_qpair_get_peer_trid(struct spdk_nvmf_qpair *qpair,
762 : : struct spdk_nvme_transport_id *trid)
763 : : {
764 : 298 : return qpair->transport->ops->qpair_get_peer_trid(qpair, trid);
765 : : }
766 : :
767 : : int
768 : 0 : nvmf_transport_qpair_get_local_trid(struct spdk_nvmf_qpair *qpair,
769 : : struct spdk_nvme_transport_id *trid)
770 : : {
771 : 0 : return qpair->transport->ops->qpair_get_local_trid(qpair, trid);
772 : : }
773 : :
774 : : int
775 : 12620 : nvmf_transport_qpair_get_listen_trid(struct spdk_nvmf_qpair *qpair,
776 : : struct spdk_nvme_transport_id *trid)
777 : : {
778 : 12620 : return qpair->transport->ops->qpair_get_listen_trid(qpair, trid);
779 : : }
780 : :
781 : : void
782 : 41945 : nvmf_transport_qpair_abort_request(struct spdk_nvmf_qpair *qpair,
783 : : struct spdk_nvmf_request *req)
784 : : {
785 [ + - ]: 41945 : if (qpair->transport->ops->qpair_abort_request) {
786 : 41945 : qpair->transport->ops->qpair_abort_request(qpair, req);
787 : : }
788 : 41945 : }
789 : :
790 : : bool
791 : 301 : spdk_nvmf_transport_opts_init(const char *transport_name,
792 : : struct spdk_nvmf_transport_opts *opts, size_t opts_size)
793 : : {
794 : : const struct spdk_nvmf_transport_ops *ops;
795 : 301 : struct spdk_nvmf_transport_opts opts_local = {};
796 : :
797 : 301 : ops = nvmf_get_transport_ops(transport_name);
798 [ + + ]: 301 : if (!ops) {
799 : 5 : SPDK_ERRLOG("Transport type %s unavailable.\n", transport_name);
800 : 5 : return false;
801 : : }
802 : :
803 [ + + ]: 296 : if (!opts) {
804 : 5 : SPDK_ERRLOG("opts should not be NULL\n");
805 : 5 : return false;
806 : : }
807 : :
808 [ + + ]: 291 : if (!opts_size) {
809 : 5 : SPDK_ERRLOG("opts_size inside opts should not be zero value\n");
810 : 5 : return false;
811 : : }
812 : :
813 : 286 : opts_local.association_timeout = NVMF_TRANSPORT_DEFAULT_ASSOCIATION_TIMEOUT_IN_MS;
814 : 286 : opts_local.acceptor_poll_rate = SPDK_NVMF_DEFAULT_ACCEPT_POLL_RATE_US;
815 : 286 : opts_local.disable_command_passthru = false;
816 : 286 : ops->opts_init(&opts_local);
817 : :
818 : 286 : nvmf_transport_opts_copy(opts, &opts_local, opts_size);
819 : :
820 : 286 : return true;
821 : : }
822 : :
823 : : void
824 : 14622974 : spdk_nvmf_request_free_buffers(struct spdk_nvmf_request *req,
825 : : struct spdk_nvmf_transport_poll_group *group,
826 : : struct spdk_nvmf_transport *transport)
827 : : {
828 : : uint32_t i;
829 : :
830 [ + + ]: 51978583 : for (i = 0; i < req->iovcnt; i++) {
831 : 37355609 : spdk_iobuf_put(group->buf_cache, req->iov[i].iov_base, req->iov[i].iov_len);
832 : 37355609 : req->iov[i].iov_base = NULL;
833 : 37355609 : req->iov[i].iov_len = 0;
834 : : }
835 : 14622974 : req->iovcnt = 0;
836 : 14622974 : req->data_from_pool = false;
837 : 14622974 : }
838 : :
839 : : static int
840 : 37355954 : nvmf_request_set_buffer(struct spdk_nvmf_request *req, void *buf, uint32_t length,
841 : : uint32_t io_unit_size)
842 : : {
843 : 37355954 : req->iov[req->iovcnt].iov_base = buf;
844 : 37355954 : req->iov[req->iovcnt].iov_len = spdk_min(length, io_unit_size);
845 : 37355954 : length -= req->iov[req->iovcnt].iov_len;
846 : 37355954 : req->iovcnt++;
847 : :
848 : 37355954 : return length;
849 : : }
850 : :
851 : : static int
852 : 30 : nvmf_request_set_stripped_buffer(struct spdk_nvmf_request *req, void *buf, uint32_t length,
853 : : uint32_t io_unit_size)
854 : : {
855 : 30 : struct spdk_nvmf_stripped_data *data = req->stripped_data;
856 : :
857 : 30 : data->iov[data->iovcnt].iov_base = buf;
858 : 30 : data->iov[data->iovcnt].iov_len = spdk_min(length, io_unit_size);
859 : 30 : length -= data->iov[data->iovcnt].iov_len;
860 : 30 : data->iovcnt++;
861 : :
862 : 30 : return length;
863 : : }
864 : :
865 : : static void nvmf_request_iobuf_get_cb(struct spdk_iobuf_entry *entry, void *buf);
866 : :
867 : : static int
868 : 20918955 : nvmf_request_get_buffers(struct spdk_nvmf_request *req,
869 : : struct spdk_nvmf_transport_poll_group *group,
870 : : struct spdk_nvmf_transport *transport,
871 : : uint32_t length, uint32_t io_unit_size,
872 : : bool stripped_buffers)
873 : : {
874 : 20918955 : struct spdk_iobuf_entry *entry = NULL;
875 : : uint32_t num_buffers;
876 : 20918955 : uint32_t i = 0;
877 : : void *buffer;
878 : :
879 : : /* If the number of buffers is too large, then we know the I/O is larger than allowed.
880 : : * Fail it.
881 : : */
882 [ - + ]: 20918955 : num_buffers = SPDK_CEIL_DIV(length, io_unit_size);
883 [ - + ]: 20918955 : if (spdk_unlikely(num_buffers > NVMF_REQ_MAX_BUFFERS)) {
884 : 0 : return -EINVAL;
885 : : }
886 : :
887 : : /* Use iobuf queuing only if transport supports it */
888 [ + + ]: 20918955 : if (transport->ops->req_get_buffers_done != NULL) {
889 : 14371519 : entry = &req->iobuf.entry;
890 : : }
891 : :
892 [ + + ]: 51979053 : while (i < num_buffers) {
893 : 39366856 : buffer = spdk_iobuf_get(group->buf_cache, spdk_min(io_unit_size, length), entry,
894 : : nvmf_request_iobuf_get_cb);
895 [ + + ]: 39366856 : if (spdk_unlikely(buffer == NULL)) {
896 : 8306758 : req->iobuf.remaining_length = length;
897 : 8306758 : return -ENOMEM;
898 : : }
899 [ + + ]: 31060098 : if (stripped_buffers) {
900 : 30 : length = nvmf_request_set_stripped_buffer(req, buffer, length, io_unit_size);
901 : : } else {
902 : 31060068 : length = nvmf_request_set_buffer(req, buffer, length, io_unit_size);
903 : : }
904 : 31060098 : i++;
905 : : }
906 : :
907 [ - + ]: 12612197 : assert(length == 0);
908 : 12612197 : req->data_from_pool = true;
909 : :
910 : 12612197 : return 0;
911 : : }
912 : :
913 : : static void
914 : 6295886 : nvmf_request_iobuf_get_cb(struct spdk_iobuf_entry *entry, void *buf)
915 : : {
916 : 6295886 : struct spdk_nvmf_request *req = SPDK_CONTAINEROF(entry, struct spdk_nvmf_request, iobuf.entry);
917 : 6295886 : struct spdk_nvmf_transport *transport = req->qpair->transport;
918 : 6295886 : struct spdk_nvmf_poll_group *group = req->qpair->group;
919 : 6295886 : struct spdk_nvmf_transport_poll_group *tgroup = nvmf_get_transport_poll_group(group, transport);
920 : 6295886 : uint32_t length = req->iobuf.remaining_length;
921 : 6295886 : uint32_t io_unit_size = transport->opts.io_unit_size;
922 : : int rc;
923 : :
924 [ - + ]: 6295886 : assert(tgroup != NULL);
925 : :
926 : 6295886 : length = nvmf_request_set_buffer(req, buf, length, io_unit_size);
927 : 6295886 : rc = nvmf_request_get_buffers(req, tgroup, transport, length, io_unit_size, false);
928 [ + + ]: 6295886 : if (rc == 0) {
929 : 398210 : transport->ops->req_get_buffers_done(req);
930 : : }
931 : 6295886 : }
932 : :
933 : : int
934 : 14623049 : spdk_nvmf_request_get_buffers(struct spdk_nvmf_request *req,
935 : : struct spdk_nvmf_transport_poll_group *group,
936 : : struct spdk_nvmf_transport *transport,
937 : : uint32_t length)
938 : : {
939 : : int rc;
940 : :
941 [ - + ]: 14623049 : assert(nvmf_transport_use_iobuf(transport));
942 : :
943 : 14623049 : req->iovcnt = 0;
944 : 14623049 : rc = nvmf_request_get_buffers(req, group, transport, length, transport->opts.io_unit_size, false);
945 [ + + + + ]: 14623049 : if (spdk_unlikely(rc == -ENOMEM && transport->ops->req_get_buffers_done == NULL)) {
946 : 2010872 : spdk_nvmf_request_free_buffers(req, group, transport);
947 : : }
948 : :
949 : 14623049 : return rc;
950 : : }
951 : :
952 : : static int
953 : 0 : nvmf_request_get_buffers_abort_cb(struct spdk_iobuf_channel *ch, struct spdk_iobuf_entry *entry,
954 : : void *cb_ctx)
955 : : {
956 : 0 : struct spdk_nvmf_request *req, *req_to_abort = cb_ctx;
957 : :
958 : 0 : req = SPDK_CONTAINEROF(entry, struct spdk_nvmf_request, iobuf.entry);
959 [ # # ]: 0 : if (req != req_to_abort) {
960 : 0 : return 0;
961 : : }
962 : :
963 : 0 : spdk_iobuf_entry_abort(ch, entry, spdk_min(req->iobuf.remaining_length,
964 : : req->qpair->transport->opts.io_unit_size));
965 : 0 : return 1;
966 : : }
967 : :
968 : : bool
969 : 0 : nvmf_request_get_buffers_abort(struct spdk_nvmf_request *req)
970 : : {
971 : 0 : struct spdk_nvmf_transport_poll_group *tgroup = nvmf_get_transport_poll_group(req->qpair->group,
972 : 0 : req->qpair->transport);
973 : : int rc;
974 : :
975 [ # # ]: 0 : assert(tgroup != NULL);
976 : :
977 : 0 : rc = spdk_iobuf_for_each_entry(tgroup->buf_cache, &tgroup->buf_cache->small,
978 : : nvmf_request_get_buffers_abort_cb, req);
979 [ # # ]: 0 : if (rc == 1) {
980 : 0 : return true;
981 : : }
982 : :
983 : 0 : rc = spdk_iobuf_for_each_entry(tgroup->buf_cache, &tgroup->buf_cache->large,
984 : : nvmf_request_get_buffers_abort_cb, req);
985 : 0 : return rc == 1;
986 : : }
987 : :
988 : : void
989 : 0 : nvmf_request_free_stripped_buffers(struct spdk_nvmf_request *req,
990 : : struct spdk_nvmf_transport_poll_group *group,
991 : : struct spdk_nvmf_transport *transport)
992 : : {
993 : 0 : struct spdk_nvmf_stripped_data *data = req->stripped_data;
994 : : uint32_t i;
995 : :
996 [ # # ]: 0 : for (i = 0; i < data->iovcnt; i++) {
997 : 0 : spdk_iobuf_put(group->buf_cache, data->iov[i].iov_base, data->iov[i].iov_len);
998 : : }
999 : 0 : free(data);
1000 : 0 : req->stripped_data = NULL;
1001 : 0 : }
1002 : :
1003 : : int
1004 : 40 : nvmf_request_get_stripped_buffers(struct spdk_nvmf_request *req,
1005 : : struct spdk_nvmf_transport_poll_group *group,
1006 : : struct spdk_nvmf_transport *transport,
1007 : : uint32_t length)
1008 : : {
1009 : 40 : uint32_t block_size = req->dif.dif_ctx.block_size;
1010 : 40 : uint32_t data_block_size = block_size - req->dif.dif_ctx.md_size;
1011 [ - + ]: 40 : uint32_t io_unit_size = transport->opts.io_unit_size / block_size * data_block_size;
1012 : : struct spdk_nvmf_stripped_data *data;
1013 : : uint32_t i;
1014 : : int rc;
1015 : :
1016 : : /* We don't support iobuf queueing with stripped buffers yet */
1017 [ - + ]: 40 : assert(transport->ops->req_get_buffers_done == NULL);
1018 : :
1019 : : /* Data blocks must be block aligned */
1020 [ + + ]: 70 : for (i = 0; i < req->iovcnt; i++) {
1021 [ + + + + ]: 50 : if (req->iov[i].iov_len % block_size) {
1022 : 20 : return -EINVAL;
1023 : : }
1024 : : }
1025 : :
1026 : 20 : data = calloc(1, sizeof(*data));
1027 [ - + ]: 20 : if (data == NULL) {
1028 : 0 : SPDK_ERRLOG("Unable to allocate memory for stripped_data.\n");
1029 : 0 : return -ENOMEM;
1030 : : }
1031 : 20 : req->stripped_data = data;
1032 : 20 : req->stripped_data->iovcnt = 0;
1033 : :
1034 : 20 : rc = nvmf_request_get_buffers(req, group, transport, length, io_unit_size, true);
1035 [ - + ]: 20 : if (rc == -ENOMEM) {
1036 : 0 : nvmf_request_free_stripped_buffers(req, group, transport);
1037 : 0 : return rc;
1038 : : }
1039 : 20 : return rc;
1040 : : }
|